【问题标题】:After main thread call pthread_exit, it turn into zombie.something wrong?主线程调用pthread_exit后,变成了zombie。有什么问题吗?
【发布时间】:2023-03-14 06:32:02
【问题描述】:

我想使用 /proc/[pid]/task/. 枚举特定进程的线程。但是在 proc 手册页中,它说:

在多线程进程中,如果主线程已经终止(通常通过调用 pthread_exit(3)),则 /proc/[pid]/task 目录的内容不可用。

然后我写一些代码,

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

void* PrintHello(void* data){
  pthread_t tid = (pthread_t)data;
  int rc;

  rc = pthread_join(tid, NULL);
  if(rc){
    exit(1);
  } else{
    printf("Hello from new thread %d - got %d\n", pthread_self(), data);
    sleep(180);
    pthread_exit(NULL);
  }
}

int main(int argc, char* argv[]){
  int rc;
  pthread_t thread_id;
  thread_t tid;

  tid = pthread_self();
  printf("\nmain thread(%d) ", tid); 

  rc = pthread_create(&thread_id, NULL, PrintHello, (void*)tid);
  if(rc){
    printf("\n ERROR: return code from pthread_create is %d \n", rc);
    exit(1);
  }
  sleep(1);
  printf("\n Created new thread (%d) ... \n", thread_id);
  pthread_exit(NULL);
}

主线程调用pthread_exit()后,变成僵尸。 /proc/[pid]/task 目录仍然存在,但 /proc/[pid]/maps 为空。

$ ./a.out & 
 main thread(164759360) 
 Created new thread (164755200) ... 
Hello from new thread 164755200 - got 164759360

$ ps auwx |  grep a.out
spyder    5408  0.0  0.0      0     0 pts/0    Zl+  10:27   0:00 [a.out] <defunct>
spyder    5412  0.0  0.0 109400   896 pts/1    S+   10:27   0:00 grep --color=auto a.out

$ ls /proc/5408/task/
5408  5409
$ cat /proc/5408/maps 
$ cat /proc/5408/status
Name:   a.out
State:  Z (zombie)
Tgid:   5408
Pid:    5408
....
$ cat /proc/5409/maps 
00400000-00401000 r-xp 00000000 fd:02 2752690                            /home/spyder/a.out
00600000-00601000 rw-p 00000000 fd:02 2752690                            /home/spyder/a.out
018cb000-018ec000 rw-p 00000000 00:00 0                                  [heap]
3dcf000000-3dcf020000 r-xp 00000000 fd:01 139203                         /usr/lib64/ld-2.15.so
3dcf21f000-3dcf220000 r--p 0001f000 fd:01 139203                         /usr/lib64/ld-2.15.so
....

有什么问题吗?

【问题讨论】:

  • 我认为文档已经过时了。理想情况下,taskmaps 仍然可用,但认为自己很幸运,至少存在 task。并且不要依赖于在旧内核上工作,因为它可能不会......
  • 你的主进程先退出,然后你的子进程退出。但是主进程退出会导致他所有的子进程退出。这是一个冲突。
  • @MYMNeo 我不认为你明白这一点。首先它是主线程而不是主进程,我只使用 pthread_exit 退出主线程,其他线程按预期继续。我的问题是为什么主线程会变成僵尸。

标签: c linux pthreads proc


【解决方案1】:

你把这一切都搞反了。您在 PrintHello 函数上执行的函数正在加入 main() 线程,而它应该是相反的:

在您的main() 线程/函数中,您应该调用:

(void)pthread_join(thread_id, NULL);

简而言之,pthread_join() 的意思是“等到带有和标识 'thread_id' 的线程完成后再做其他事情”。您的代码基本上是在说:

  1. 启动 main() 程序逻辑
  2. 创建一个线程,做一些 printf() 和 sleep() 的事情,然后退出整个程序
  3. 同时,您创建了一个在 main() 终止之前不会执行任何操作的线程
  4. 当 main() 死机时,无论如何它都会处理所有内容,因此 PrintHello() 线程没有机会优雅地关闭,因为 join() 调用可能会失败

您可能打算这样做(请注意额外的 cmets):

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

void* PrintHello(void* data){
  pthread_t tid = (pthread_t)data;

  //pthread_join(tid, NULL);  //WRONG
  printf("Hello from new thread %d - I was launched by thread number: %d\n", pthread_self(), data);
  sleep(180); //Sleep for 3 minutes, for no reason really
  pthread_exit(NULL); //All done in this thread
}

int main(int argc, char* argv[]){
  int rc;
  pthread_t thread_id;
  long int tid;

  tid = pthread_self();

  rc = pthread_create(&thread_id, NULL, PrintHello, (void*)tid);
  if(rc) {
    printf("\n ERROR: return code from pthread_create is %d; Thread probably didn't get created\n", rc);
    exit(1);
  }
  sleep(1); //Sleep, for no reason
  printf("\n Created new thread (%d) ... Now let's wait for it to finish\n", thread_id);
  pthread_join(thread_id, NULL); //Wait for the child thread to finish it's work
  return 0; //All done!
}

如果我的假设是正确的,请指出是这种情况,我可以做一些进一步的更正。祝你好运!

【讨论】:

  • 是的,这是正常的方式,但是根据手册,主线程可以调用pthread_exit退出。其他线程运行正常,之后 /proc/[pid]/task 不可用。但我的示例代码显示,task 目录很好。但主线程变成僵尸线程。正如 R.. 所说,也许文件已经过时了。
  • @spyder 如果你想退出主线程同时让创建的线程继续,你必须分离你创建的线程。参见例如pthread_detach.
【解决方案2】:

根据我对 pthreads 库如何工作的理解,我认为僵尸线程的原因是加入 通常 与主线程会丢弃它的资源,因为主线程返回一个状态(通过主函数的返回)可能并且在某些情况下预期会被父进程消耗(即,通过使用等待),该线程不能完全销毁,直到线程组完全退出(即,整个过程已经退出)。如果它以某种方式被允许将 pthread_exit 调用的值返回给父进程,那么父进程会认为子进程已经退出,这是不正确的,因为 PrintHello 函数将仍在运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多