【问题标题】:pthread_exit vs return in posix threadpthread_exit 与 posix 线程中的返回
【发布时间】:2013-12-04 23:13:36
【问题描述】:

这是我的程序,只是为了找出 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 *)&foo);”退出线程函数“thr_fun1()”时它应该调用对象 foo 的析构函数,但是当我调用“pthread_exit((void *)&foo);”时它不应该调用析构函数从函数“thr_fun1()”返回到 main。

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

这不是我猜的行为。只能在“return((void *)&foo);”中调用析构函数仅限大小写。

如果我错了,请验证我?

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    您的代码存在严重问题。具体来说,您使用局部变量作为 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 *)&amp;foo) )将导致检索并尝试取消引用此地址的任何代码出现问题。

    【讨论】:

    • 根据 Pthreads 规范,它写道“如果从取消清理处理程序或析构函数调用 pthread_exit() 的行为是未定义的,该函数是由于对 pthread_exit 的隐式或显式调用而调用的()。”在我的例子中,我不是从析构函数或清理处理函数调用 pthread_exit 。我从线程本身调用它。请提供更正确的详细信息
    • @Santosh Sahu 该规范特别指出“线程终止后,访问线程的本地(自动)变量的结果是未定义的。因此,不应引用退出线程的局部变量用于 pthread_exit() value_ptr 参数值。”,这正是您的示例正在做的事情。现在,关于那个否决票......
    【解决方案2】:

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

    【讨论】:

    • 我已经改变了问题。请在任何编辑器中编译并回复。
    • “其他不好的问题”包括不释放以这种方式终止的线程获取/拥有的同步对象(互斥体等)的所有权。
    【解决方案3】:

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

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


    注意:正如其他答案/cmets 所提到的,返回本地地址无论如何都行不通,但这不是问题的重点。如果返回一些其他有效地址(或空指针)而不是 &amp;foo,则在销毁 foo 时会得到相同的行为。

    【讨论】:

      猜你喜欢
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多