pthread_exit vs posix线程中的返回

时间:2013-11-20 19:09:36

标签: c++ multithreading

这是我的程序,只是为了找到pthread_exit和从线程返回的区别。

struct foo{
    int a,b,c,d;
    ~foo(){cout<<"foo destructor called"<<endl;}
};
//struct foo foo={1,2,3,4};
void printfoo(const char *s, const struct foo *fp)
{
    cout<<s;
    cout<<"struct at 0x"<<(unsigned)fp<<endl;
    cout<<"foo.a="<<fp->a<<endl;
    cout<<"foo.b="<<fp->b<<endl;
    cout<<"foo.c="<<fp->c<<endl;
    cout<<"foo.d="<<fp->d<<endl;
}
void *thr_fn1(void *arg)
{
    struct foo foo={1,2,3,4};
    printfoo("thread1:\n",&foo);
    pthread_exit((void *)&foo);
    //return((void *)&foo);
}
int main(int argc, char *argv[])
{
    int err;
    pthread_t tid1,tid2;
    struct foo *fp;
    err=pthread_create(&tid1,NULL,thr_fn1,NULL);
    if(err!=0)
            cout<<"can't create thread 1"<<endl;
    err=pthread_join(tid1,(void **)&fp);
    if(err!=0)
            cout<<"can't join with thread 1"<<endl;
    exit(0);
}

在“* thr_fn1”线程函数中,我创建了一个对象foo。

根据网站pthread_exit vs. return 当我使用“return((void *)&amp; foo)退出线程函数”thr_fun1()“时;”它应该调用对象foo的析构函数,但是当我调用“pthread_exit((void *)&amp; foo)时,它不应该调用析构函数;”从函数“thr_fun1()”返回main。

但在两种情况下都使用“return((void *)&amp; foo);”或“pthread_exit((void *)&amp; foo);”调用函数“thr_fun1()”中的本地对象“foo”。

这不是我猜的行为。应该只在“return((void *)&amp; foo);”中调用析构函数。仅限案例。

如果我错了,请核实我?

3 个答案:

答案 0 :(得分:4)

是的,没错。 pthread_exit()立即退出当前线程,而不调用堆栈上方对象的任何析构函数。如果您使用C ++进行编码,则应确保始终从线程过程中return,或者仅从最底层的堆栈帧中调用pthread_exit(),而在该帧中没有具有析构函数的对象或任何更高的帧;否则,您将泄漏资源或导致其他不良问题。

答案 1 :(得分:4)

您的代码存在严重问题。具体来说,您使用局部变量作为pthread_exit()的退出值:

void *thr_fn1(void *arg)
{
    struct foo foo={1,2,3,4};
    printfoo("thread1:\n",&foo);
    pthread_exit((void *)&foo);
    //return((void *)&foo);
}

根据Pthreads spec,“线程终止后,线程的本地(自动)变量访问结果未定义。

因此,从线程函数返回堆栈分配变量的地址作为线程退出值(在您的情况下为pthread_exit((void *)&foo))将导致任何检索并尝试取消引用该地址的代码出现问题。 / p>

答案 2 :(得分:2)

pthread_exit()抛出异常,导致堆栈展开,并为本地调用析构函数。有关详细信息,请参阅https://stackoverflow.com/a/11452942/12711

抛出的异常属于abi::__forced_unwind类型(来自cxxabi.h);互联网搜索可以为您提供更多详细信息。


注意:正如其他答案/评论所提到的那样,返回本地地址无论如何都不会起作用,但这就是问题的重点。如果返回某个其他有效地址(或空指针)而不是foo,则会获得与销毁&foo相同的行为。