如何从C中的线程返回一个值

Pet*_*ler 48 c pthreads

我是C的新手,想稍微玩一下线程.我想从一个线程中返回一些值pthread_exit()

我的代码如下:

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

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;

   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望程序输出"42 \n",但它输出一个随机数.如何打印返回的值?

编辑: 根据第一个答案,问题是我返回指向局部变量的指针.返回/存储多个线程的变量的最佳做法是什么?全局哈希表?

提前致谢

小智 46

您正在返回局部变量的地址,当线程函数退出时,该地址变量不再存在.无论如何,为什么要调用pthread_exit?为什么不简单地从线程函数返回一个值?

void *myThread()
{
   return (void *) 42;
}
Run Code Online (Sandbox Code Playgroud)

然后在主要:

printf("%d\n",(int)status);   
Run Code Online (Sandbox Code Playgroud)

如果你需要返回一个复杂的值这样的结构,最简单的方法是通过malloc()动态分配它并返回一个指针.当然,启动该线程的代码将负责释放内存.

  • `pthread_exit`就像`exit`.它允许你的线程提前挽救,就像程序可以提前纾困一样,并且可以从线程中的任何代码调用它,而要返回,你必须回到线程入口点.当然,区别在于,如果您尝试退出而不是通过入口点退出,则在线程中您很可能会将资源泄漏到整个地方. (6认同)
  • 将42转换为`void*`不是UB.它是实现定义的.现实世界的实现将其定义为预期. (5认同)
  • 如果你实际上是指"为什么不",那么之所以不是因为将42转换为指针类型是未定义的行为.当然,如果它做了什么坏事,那么它就是其中一个"它是一个C实现,Jim,但不是我们所知道的"时刻. (3认同)
  • 但结果可能是陷阱表示.我在两个方面对陷阱持谨慎态度.首先,我认为避免编写可以读取它们的代码是相当合理的,即使是标准允许的方式,因为相关文本仅提到左值.其次,我忽略了这样一个事实:在现实生活中,除了浮点类型之外,没有任何实现可以定义它的类型.在仅仅依靠标准,通过共同的实施实践,以及咬人的错误假设的滑动规模上,在两种方式下都不那么谨慎是一个相当安全的赌注. (2认同)

Ste*_*sop 25

您已经返回了一个指向局部变量的指针.即使没有涉及线程,这也很糟糕.

执行此操作的常用方法是,当启动的线程是连接的同一个线程时,将在调用者管理的位置传递指向int的指针,作为pthread_create的第4个参数.然后它成为线程入口点的(唯一)参数.您可以(如果您愿意)使用线程退出值来表示成功:

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

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果您必须使用结构的线程退出值,那么您将必须动态分配它(并确保加入该线程的任何人释放它).但这并不理想.

  • 我刚刚发现了这个,但是根据http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html你不需要在你的线程函数调用中使用pthread_exit."线程终止的正常机制是从启动它的pthread_create()调用中指定的例程返回.pthread_exit()函数提供线程终止的能力,而不需要从启动例程返回该线程,从而提供类似于exit()的功能." pthread_exit应该用于提前终止. (2认同)

小智 22

这是一个正确的解决方案.在这种情况下,tdata在主线程中分配,并且线程有一个空间来放置其结果.

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

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是这里最干净的例子 - 我很惊讶它没有得到更高的投票。特别是它表明在调用级别管理存储是正确的做法 - 而且指针可用于传递更复杂的结构 - 传入和传出。 (5认同)

Mes*_*ssa 5

我认为您必须将数字存储在堆上。该int ret变量在堆栈上,并在函数执行结束时被销毁myThread

void *myThread()
{
       int *ret = malloc(sizeof(int));
       if (ret == NULL) {
           // ...
       }
       *ret = 42;
       pthread_exit(ret);
}
Run Code Online (Sandbox Code Playgroud)

free当您不需要它时,请不要忘记它:)

另一个解决方案是像Neil Butterworth所建议的那样,将数字作为指针的值返回。

  • 它不是“愚蠢的”,它是C类型系统的局限性。为了通过pthreads系统返回任意类型的参数,您需要一个Python样式的对象系统,其中的变量没有类型,只有值有,否则您需要大量的C ++模板技术。以完全相同的方式,您只能从线程入口点返回“ void *”,而不能返回(例如)双精度值。 (5认同)