关于 pthread_exit 释放自动变量的困惑

Posted

技术标签:

【中文标题】关于 pthread_exit 释放自动变量的困惑【英文标题】:Confusion regarding pthread_exit freeing of automatic variables 【发布时间】:2013-03-29 08:45:02 【问题描述】:

根据this

"如果一个线程调用pthread_exit,但是,C++ 不保证析构函数是 调用线程堆栈上的所有自动变量。一个聪明的方法来恢复这个 功能是在线程函数的顶层调用 pthread_exit 抛出一个特殊的异常”。

后面跟着这段代码

class ThreadExitException


public:
ThreadExitException (void* return_value)
                    : thread_return_value_ (return_value)  

void* DoThreadExit ()

 pthread_exit (thread_return_value_);


private:
void* thread_return_value_;

;

void do_some_work ()

while (1) 

 /* Do some useful things here...*/
 if (should_exit_thread_immediately ())
 throw ThreadExitException (/* thread’s return value = */ NULL);



void* thread_function (void*)

 try 
 
  do_some_work ();
 
catch (ThreadExitException ex) 

 ex.DoThreadExit ();


return NULL;

据我了解... 如果调用 pthread_exit ,则可能不会调用堆栈的所有自动变量的析构函数。 因此我们使用异常处理来确保为所有变量调用析构函数。 (引自解释:“通过抛出 ThreadExitException 而不是 直接调用pthread_exit,异常被***线程函数捕获,线程栈上的所有局部变量都会被正确销毁 异常渗出。”

根据pthread_exit的手册页

“任何由 pthread_cleanup_push(3) 建立的尚未被弹出的清理处理程序都会被弹出(与它们被推送的顺序相反)并且 执行。 如果线程有任何线程特定的数据,则在执行清理处理程序后,调用相应的析构函数,在 一个未指定的订单”。

这表示函数调用了析构函数,所以自动变量会被释放?那为什么要使用代码中演示的异常处理呢?

【问题讨论】:

【参考方案1】:

线程特定数据与您所理解的不同。线程特定数据是已设置的全局数据,以便每个线程获得全局数据的单独副本。因此,线程特定的数据并不像您假设的那样存在于堆栈中。

请参阅here 了解更多信息(以及 pthread 示例)。

【讨论】:

所以pthread_exit 有可能会导致线程退出而不清除局部变量(非线程特定数据)?因此,我们使用异常处理采取预防措施以确保变量超出范围(假设它们在堆栈上)并自动销毁?我说对了吗?【参考方案2】:

不,它说 析构函数 是针对特定于线程的数据调用的。这与在线程调用堆栈中的自动变量上调用 C++ 析构函数完全不同。

有关与线程特定数据关联的析构函数的文档,请参阅 man pthread_key_create

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

[...] 可选的析构函数可以与每个键值相关联。在线程退出时,如果键值具有非 NULL 析构指针,并且线程具有与该键关联的非 NULL 值,则将键的值设置为 NULL,然后调用指向的函数以前关联的值作为其唯一参数。如果线程退出时存在多个析构函数,则未指定析构函数调用的顺序。 [...]

【讨论】:

以上是关于关于 pthread_exit 释放自动变量的困惑的主要内容,如果未能解决你的问题,请参考以下文章

信号处理程序中的 pthread_exit()

linux c编程:线程退出

关于 CoffeeScript 变量范围的困惑

使用 AppDelegate 的变量作为全局变量 - 关于释放/保留的问题

关于堆栈的讲解

何时使用自动释放变量? [复制]