Linux pthread_exit 与返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3844678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:33:35  来源:igfitidea点击:

pthread_exit vs. return

clinuxpthreadsvalgrind

提问by

I have a joinable pthread runner function defined as below:

我有一个可连接的 pthread runner 函数,定义如下:

void *sumOfProducts(void *param)
{
...
pthread_exit(0);
}

This thread is supposed to join the main thread.

这个线程应该加入主线程。

Whenever I ran my program through Valgrind I would get the following leaks:

每当我通过 Valgrind 运行我的程序时,我都会遇到以下泄漏

LEAK SUMMARY:
   definitely lost: 0 bytes in 0 blocks
   indirectly lost: 0 bytes in 0 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 968 bytes in 5 blocks
        suppressed: 0 bytes in 0 blocks

ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 10)

I checked the man page for pthreads which said:

我检查了 pthreads 的手册页,其中说:

  The new thread terminates in one of the following ways:

   * It  calls  pthread_exit(3),  specifying  an exit status value that is
     available  to  another  thread  in  the  same  process   that   calls
     pthread_join(3).

   * It  returns  from  start_routine().   This  is  equivalent to calling
     pthread_exit(3) with the value supplied in the return statement.

   * It is canceled (see pthread_cancel(3)).

   * Any of the threads in the process calls exit(3), or the  main  thread
     performs  a  return  from main().  This causes the termination of all
     threads in the process.

Miraculously, when I replaced the pthread_exit() with a return statement, the leaks disappeared.

奇迹般地,当我用 return 语句替换 pthread_exit() 时,泄漏消失了

return(NULL);

My actual question is three-pronged:

我的实际问题是三管齐下的:

  1. Can someone explain why the return statement gave no leaks?
  2. Is there some fundamental difference between both statements, in relation to exiting from threads?
  3. If so, when should one be preferred over the other?
  1. 有人可以解释为什么 return 语句没有泄漏吗?
  2. 关于退出线程,这两个语句之间是否存在一些根本区别?
  3. 如果是这样,什么时候应该优先选择一个?

采纳答案by caf

The following minimal test case exhibits the behaviour you describe:

以下最小测试用例展示了您描述的行为:

#include <pthread.h>
#include <unistd.h>

void *app1(void *x)
{
    sleep(1);
    pthread_exit(0);
}

int main()
{
    pthread_t t1;

    pthread_create(&t1, NULL, app1, NULL);
    pthread_join(t1, NULL);

    return 0;
}

valgrind --leak-check=full --show-reachable=yesshows 5 blocks allocated from functions called by pthread_exit()that is unfreed but still reachable at process exit. If the pthread_exit(0);is replaced by return 0;, the 5 blocks are not allocated.

valgrind --leak-check=full --show-reachable=yes显示从被调用的函数分配的 5 个块pthread_exit()未释放但在进程退出时仍可访问。如果pthread_exit(0);替换为return 0;,则不分配 5 个块。

However, if you test creating and joining large numbers of threads, you will find that the amount of unfreed memory in use at exit does notincrease. This, and the fact that it is still reachable, indicates that you're just seeing an oddity of the glibc implementation. Several glibc functions allocate memory with malloc()the first time they're called, which they keep allocated for the remainder of the process lifetime. glibc doesn't bother to free this memory at process exit, since it knows that the process is being torn down anyway - it'd just be a waste of CPU cycles.

但是,如果您测试创建和加入大量线程,您会发现退出时使用的未释放内存量并没有增加。这一点以及它仍然可以访问的事实表明您只是看到了 glibc 实现的一个奇怪之处。几个 glibc 函数malloc()在第一次被调用时分配内存,它们在进程生命周期的剩余时间里保持分配。glibc 不会在进程退出时释放这些内存,因为它知道进程无论如何都会被拆除 - 这只会浪费 CPU 周期。

回答by Doug

Are you actually using C++, by any chance? To clarify - your source file ends with a .cextension, and you are compiling it with gcc, not g++?

你真的在使用 C++ 吗?澄清一下 - 您的源文件以.c扩展名结尾,并且您正在编译它gcc,而不是g++?

It seems reasonably likely that your function is allocating resources that you expect to be cleaned up automatically when the function returns. Local C++ objects like std::vectoror std::stringdo this, and their destructors probably won't be run if you call pthread_exit, but would be cleaned up if you just return.

您的函数很可能正在分配您希望在函数返回时自动清除的资源。本地 C++ 对象喜欢std::vectorstd::string执行此操作,如果您调用pthread_exit,它们的析构函数可能不会运行,但如果您只是返回,则会被清除。

My preference is to avoid low-level APIs such as pthread_exit, and always just return from the thread function, where possible. They're equivalent, except that pthread_exitis a de-facto flow-control construct that bypasses the language you're using, but returndoesn't.

我的偏好是避免使用诸如pthread_exit, 之类的低级 API ,并且在可能的情况下始终只从线程函数返回。它们是等价的,除了它pthread_exit是一个事实上的流控制结构,它绕过了你正在使用的语言,但return没有。

回答by Jens Gustedt

I have the experience that valgrind has difficulties of tracking the storage that is allocated for the state of joinable threads. (This goes in the same direction as caf indicates.)

我的经验是 valgrind 很难跟踪为可连接线程的状态分配的存储。(这与 caf 指示的方向相同。)

Since it seems that you always return a value of 0I guess that you perhaps need to join your threads from an application point of view? If so consider of launching them detached from the start, this avoids the allocation of that memory.

既然您似乎总是返回一个值,0我猜您可能需要从应用程序的角度加入您的线程?如果考虑从一开始就分离启动它们,则可以避免分配该内存。

The downside is that you either have:

缺点是你要么有:

  1. to implement your own barrier at the end of your main. If you know the number of threads beforehand, a simple statically allocated pthread_barrierwould do.
  2. or to exit you mainwith pthread_exitsuch that you don't kill the rest of the running threads that might not yet be finished.
  1. 在您的main. 如果你事先知道线程的数量,一个简单的静态分配 pthread_barrier就可以了。
  2. 或者让您退出mainpthread_exit这样您就不会杀死可能尚未完成的其余正在运行的线程。

回答by Steven S

Not sure if you're still interested in this, but I am currently debugging a similar situation. Threads that use pthread_exitcause valgrind to report reachable blocks. The reason seems to be fairly well explained here:

不确定您是否仍然对此感兴趣,但我目前正在调试类似的情况。使用的线程pthread_exit会导致 valgrind 报告可访问的块。原因似乎在这里得到了很好的解释:

https://bugzilla.redhat.com/show_bug.cgi?id=483821

https://bugzilla.redhat.com/show_bug.cgi?id=483821

Essentially it seems pthread_exitcauses a dlopenwhich is never cleaned up explicitly when the process exits.

从本质上讲,它似乎pthread_exit会导致dlopen进程退出时从未明确清除的a 。

回答by Dustin Oprea

It looks like calling exit() (and, apparently, pthread_exit()) leaves automatically-allocated variables allocated. You must either return or throw in order to properly unwind.

看起来调用 exit() (显然还有 pthread_exit() )会留下自动分配的变量。您必须返回或抛出才能正确放松。

Per C++ valgrind possible leaks on STL string:

每个C++ valgrind 在 STL 字符串上可能存在泄漏

@Klaim: I don't see where that document says that I am wrong, but if it does then it is wrong. To quote the C++ standard (§18.3/8): "Automatic objects are not destroyed as a result of calling exit()." – James McNellis Sep 10 '10 at 19:11

@Klaim:我看不出该文件在哪里说我错了,但如果确实如此,那就错了。引用 C++ 标准(第 18.3/8 节):“调用 exit() 不会破坏自动对象。” – 詹姆斯·麦克内利斯 2010 年 9 月 10 日 19:11

Since doing a "return 0" instead of "pthread_exit(0)" seemed to solve your problem (and mine.. thanks), I'm assuming that the behavior is similar between the two.

由于执行“return 0”而不是“pthread_exit(0)”似乎解决了您的问题(还有我的……谢谢),我假设两者之间的行为相似。