【问题标题】:How can I pass an array as a return value through a thread?如何通过线程将数组作为返回值传递?
【发布时间】:2018-09-11 05:20:37
【问题描述】:

我正在开发一个函数,该函数创建一个线程并将斐波那契数列计算为某个用户输入的值。例如,如果用户输入5,则输出将是:0 1 1 2 3 5

但是,序列必须在创建的线程中计算,并且必须在线程退出后打印出结果。

我可以创建线程并计算序列,但我需要使用pthread_exitpthread_join 将数组fibSequence[] 传递回原始线程。我无法弄清楚语法,并且找不到任何人通过数组的示例。

到目前为止我所拥有的: 我创建了一个由新创建的线程调用的函数fib_runner()。斐波那契数列被创建并放入数组fibSequence[]。我需要将它传递回主函数。我是暂时打印出函数中的序列,但是应该在main中打印出来。

谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void* fib_runner(void* arg)
{
    int *limit_ptr = (int*) arg;
    int limit = *limit_ptr;
    int fibSequence[limit];

    int size = sizeof(fibSequence)/sizeof(fibSequence[0]);
    printf("Size: %d\n", size);

    fibSequence[0] = 0;
    fibSequence[1] = 1;

    for (int i = 2; i <= size; i++)
    {
        fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
    }

    for (int i = 0; i <= size; i++)
    {
        printf("%d ", fibSequence[i]);
    }
    pthread_exit(0);
}

int main(int argc, char **argv)
{
    int limit;
    printf("Enter Number: ");
    scanf("%d", &limit);

    pthread_t tid;
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    pthread_create(&tid, &attr, fib_runner, &limit);
    pthread_join(tid, NULL);
}

【问题讨论】:

标签: c linux multithreading unix pthreads


【解决方案1】:

目前,数组是一个局部变量,所以当函数退出时它会超出范围。您需要为它动态分配内存:

int *fibSequence = malloc(sizeof(int) * limit);

然后从函数中返回这个指针:

return fibSequence;

在您的main 函数中,您然后传递一个指针的地址以接收该值。然后就可以打印数组的内容了。完成后,一定要free它:

int *fibSequence;
pthread_join(tid, (void **)&fibSequence);

for (int i = 0; i < limit; i++)
{
    printf("%d ", fibSequence[i]);
}
free(fibSequence);

另外,您的线程函数中不需要size,因为它与limit 相同,而且您当前计算它的方式无论如何都行不通,因为您现在有一个指针而不是数组. fib_runner 中的循环限制也超过了数组的末尾。退出条件应该是i &lt; size,而不是i &lt;= size

【讨论】:

  • 当我使用 return 时,这不是使 pthread_exit 无法访问吗?另外,当我使用 malloc 初始化 *fibSequence 时,我应该在使用 limit 初始化它的大小之前还是之后这样做?
  • @NamitPatel 从线程函数返回与调用pthread_exit 相同。它们是可以互换的。对于fibSequence,上面调用malloc 的行就是您所需要的(加上错误检查以确保malloc 成功)。
  • 好的,我删除了 pthread_exit,我不知道返回是一样的。另外,当我调用 malloc 时,我不认为它正在初始化正确数量的元素。例如,当我输入 5 作为输入时,它会打印 0 1 0 0 0
  • 没关系,这是我的错误。在我的 for 循环中使用大小而不是限制,所以它提前结束了。谢谢您的帮助!程序有效!
【解决方案2】:

您必须将void * 的值传递给pthread_exit,即pthread_exit(( void * ) &amp;fibSequence,一旦调用该函数,传入的值将填充pthread_join 的第二个参数,第二个参数将是一个指针指向一个指针void **,它将保存传递给pthred_exit的值

【讨论】:

    【解决方案3】:

    在一个进程中运行的所有线程共享相同的地址空间、文件描述符、堆栈和其他与进程相关的属性。

    线程根据定义共享内存,除了堆栈和局部变量之外,它们不拥有任何东西;

    如果你将fibSequence[limit]设为全局,那么所有线程都可以访问它。

    您还可以在main 的堆栈上声明fibSequence[limit],并将指向它的指针传递给您的线程。

    要传递多个参数,将它们包装在一个结构中很方便。 以下解决方案采用:

    struct arg_struct {
        int limit;
        int *ptrFib;
    }args;
    

    程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    struct arg_struct {
        int limit;
        int *ptrFib;
    }args;
    
    void* fib_runner(void* arg)
    {
        struct arg_struct *a = (struct arg_struct *) arg;
        int size = a->limit;
        int * fibSequence = a->ptrFib;  
    
        fibSequence[0] = 0;
        fibSequence[1] = 1;
    
        for (int i = 2; i <= size; i++){
            fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
        }    
        pthread_exit(0);
    }
    
    int main(int argc, char **argv)
    {
        int limit;
        printf("Enter Number: ");
        scanf("%d", &limit);
        int fibSequence[limit];
    
        struct arg_struct argF;
        argF.limit = limit;
        argF.ptrFib = fibSequence;
    
        pthread_t tid;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
    
        pthread_create(&tid, &attr, fib_runner, &argF);
        pthread_join(tid, NULL);
    
        for (int i = 0; i <= limit; i++){
            printf("%d ", fibSequence[i]);
        }
    }
    

    输出:

    Enter Number: 5                                                                                                                                                                                                                                                               
    0 1 1 2 3 5 
    

    使用全局变量argF 的解决方案当然是可行的,但不太优雅。

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    struct arg_struct {
        int limit;
        int *ptrFib;
    }args;
    
    struct arg_struct argF;
    
    void* fib_runner()
    {
        int size = argF.limit;
        int * fibSequence = argF.ptrFib;
    
        fibSequence[0] = 0;
        fibSequence[1] = 1;
    
        for (int i = 2; i <= size; i++){
            fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
        }
        pthread_exit(0);
    }
    
    int main(int argc, char **argv)
    {
        int limit;
        printf("Enter Number: ");
        scanf("%d", &limit);
        int fibSequence[limit];
    
        argF.limit = limit;
        argF.ptrFib = fibSequence;
    
        pthread_t tid;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
    
        pthread_create(&tid, &attr, fib_runner, NULL);
        pthread_join(tid, NULL);
    
        for (int i = 0; i <= limit; i++){
            printf("%d ", fibSequence[i]);
        }
    }
    

    【讨论】:

    • 在文件范围内不允许使用可变长度数组,并且返回指向本地声明的数组的指针会调用未定义的行为,因为它超出了范围。
    • 我在使用这个解决方案时遇到的问题是,在 main 函数之前我没有得到 limit 的值。所以我不知道如何在用户输入之前没有限制时将其初始化为全局变量。除非有一种我没有考虑的方法。编辑:什么 dbush 说的。
    • @dbush 感谢您的评论!我没有说清楚。我的意思是在main 中声明fibSequence[limit]。这种数组的生命周期等于程序的生命周期。
    • @NamitPatel 此序列将在 C99 中工作:scanf("%d", &amp;limit); int fibSequence[limit]; 或使用 dbush 动态方法。
    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 2016-01-23
    • 2015-04-12
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多