【问题标题】:Is it OK to call pthread_exit from main?从 main 调用 pthread_exit 可以吗?
【发布时间】:2011-04-03 08:01:09
【问题描述】:

当我从main 调用pthread_exit 时,程序永远不会终止。我希望程序完成,因为我正在退出程序的唯一线程,但它不起作用。好像挂了。

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

int main(int argc, char *argv[])
{
    printf("-one-\n");

    pthread_exit(NULL);

    printf("-two-\n");
}

Process Explorer 显示(唯一的)线程处于Wait:DelayExecution 状态。

根据pthread_exit 文档:

进程应退出并退出 最后一个线程之后的状态为 0 被终止。行为应为 好像实现调用 exit() 线程中的参数为零 终止时间。

我正在使用 Dev-C++ v4.9.9.2pthreads-win32 v2.8.0.0(链接到 libpthreadGC2.a)。

库似乎没问题(例如,从main 调用pthread_selfpthread_create 工作正常)。

我不应该从main 打电话给pthread_exit 有什么理由吗?

【问题讨论】:

  • 你为什么不return 0; 而不是pthread_exit(NULL);
  • 我知道我可以 returnexit。我只想知道调用pthread_exit终止主线程是否合法。
  • 从 main() 返回与运行 pthread_exit() 非常不同。后者将让其余的活动线程完成,然后返回值 0 退出。前者将立即终止一切。

标签: c winapi pthreads exit main


【解决方案1】:

它在 pthreads 的 linux 实现中绝对是合法的,请参阅pthreads_exit 中的注释部分。它指出

为了让其他线程继续执行,主线程应该终止 通过调用 pthread_exit() 而不是 exit(3)。

此外,查看源代码here(结尾处)表明它大致转换为_endthread 或_endthreadex。那些文档here 没有提到不在初始线程中调用它。

【讨论】:

  • 那么我想它在win32实现中也应该是合法的(sourceware.org/pthreads-win32/bugs.html)。我一直在寻找一个已知的错误来解释这种行为,但我找不到它。在我看来,要么这是一个错误的行为,要么是我不应该在pthreads_win32 上调用pthread_exit 的实际原因。任何人都可以证实这些假设吗?
  • @matasierra:我在上面的答案中添加了更多细节。另外,main 实际执行的是什么?
  • 第一个 printf 实际上打印出来了,但第二个没有(如预期的那样)。问题是程序不会终止。它只是有点冻结
  • 我终于找到了问题所在。我认为这是我操作系统上的某种恶意软件。我刚刚使用反间谍软件工具对其进行了清理,现在它可以按预期工作了。哦,我的……我觉得自己很愚蠢。 @torak 我会接受你的回答。感谢您的帮助!
【解决方案2】:

这是完全合法且符合预期的行为。整个过程只有在所有线程都终止或者exit被显式或隐式调用时才结束。

main 正常返回相当于调用exit。如果您以 pthread_exit 结束 main,则您明确表示您希望其他线程继续。

【讨论】:

    【解决方案3】:

    在 Linux(CentOS Linux 版本 7.2.1511 (Core))上进行测试时,我发现主程序确实在等待“子”线程继续执行。 我也无法从 main 传递返回代码,尽管它可以指定为 pthread_exit() 的参数,正如 Raul 上面所说的,它总是返回退出代码 0:

    retval=3;
    pthread_exit(&retval);
    

    我们在使用 Clang 编译器(版本 3.4.2)和 sanitizer 选项时还观察到错误消息:

    ==5811==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7f4c090321d0 in thread T0
    #0 0x7f4c08be3e29 in __interceptor_free (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x65e29)
    #1 0x7f4c08333358 in free_key_mem (/lib64/libdl.so.2+0x1358)
    #2 0x7f4c08745bc1 in __nptl_deallocate_tsd (/lib64/libpthread.so.0+0x7bc1)
    #3 0x7f4c07771b38 in __libc_start_main (/lib64/libc.so.6+0x21b38)
    #4 0x7f4c08bfa08c in _start (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x7c08c)
    
    AddressSanitizer can not describe address in more detail (wild memory access suspected).
    SUMMARY: AddressSanitizer: bad-free ??:0 __interceptor_free
    ==5811==ABORTING
    

    【讨论】:

    • 你是不是给retval使用了一个局部变量,所以它的地址就失效了?
    【解决方案4】:

    在 main 中使用 pthread_exit 很好。当使用 pthread_exit 时,主线程将停止执行并保持僵尸(已失效)状态,直到所有其他线程退出。

    如果您在主线程中使用 pthread_exit,则无法获取其他线程的返回状态并且无法对其他线程进行清理(可以使用 pthread_join(3) 完成)。此外,最好分离线程(pthread_detach(3)),以便在线程终止时自动释放线程资源。在所有线程退出之前,共享资源不会被释放。

    在主线程不分配资源时可以使用,不需要清理。下面的代码显示了在主线程中使用 pthread_exit。 main 中的第二个 printf 不会打印,因为调用 pthread_exit 后主线程退出。 ps 输出显示了已失效的主线程。

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>
    
    void *functionC(void *);
    
    int main()
    {
            int rc;
            pthread_t th;
    
            if(rc = pthread_create(&th, NULL, &functionC, NULL))
            {
                    printf("Thread creation failed, return code %d, errno %d", rc,                 errno);
            }
    
            printf("Main thread %lu: Sleeping for 20 seconds\n", pthread_self());
            fflush(stdout);
            sleep(20);
            pthread_exit(NULL);
            printf("Main thread %lu: This will not be printed as we already called         pthread_exit\n", pthread_self());
            exit(0);
    }
    
    void *functionC(void *)
    {
            printf("Thread %lu: Sleeping for 20 second\n", pthread_self());
            sleep(20);
            printf("Thread %lu: Came out of first and sleeping again\n", pthread_self());
            sleep(20);
            printf("CThread %lu: Came out of second sleep\n", pthread_self());
    }
    

    以上代码的输出:

    Main thread 140166909204288: Sleeping for 20 seconds
    Thread 140166900684544: Sleeping for 20 second
    Thread 140166900684544: Came out of first and sleeping again
    CThread 140166900684544: Came out of second sleep
    

    ps 输出:

    root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
    0 S root      9530  9530  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
    1 S root      9530  9531  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
    0 S root      9537  9537  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep --color=auto a.out
    
    root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
    0 Z root      9530  9530  9496  0  80   0 -     0 -      17:31 pts/1    00:00:00 [a.out] <defunct>
    1 S root      9530  9531  9496  0  80   0 -  4258 hrtime 17:31 pts/1    00:00:00 ./a.out
    0 S root      9539  9539  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep     --color=auto a.out`
    

    请查看博客Tech Easy 了解有关线程的更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 2023-02-20
      • 2012-08-10
      • 1970-01-01
      • 2011-12-24
      • 2013-01-08
      相关资源
      最近更新 更多