Linux C使用pthread进行多线程编程时,有一个注意点:新启动的子线程一定要在主线程或启动它的父线程中join,或者本身被设置为detach,否则会引起资源泄露,资源比如每个线程都有自己的运行stack,内核中的task_stuct数据结够等。有点儿类似父子进程中的子进程退出没有被父进程join就会变成僵尸进程一样。
文章后面的例子最终会导致资源耗尽 pthread_create 返回 11这个错误码. 它对应的宏是EAGAIN,意思就是操作系统没有资源创建新的线程了。
根据 https://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_create.html 说明:
[EAGAIN]
The system lacked the necessary resources to create another thread, or the system-imposed limit on the total number of threads in a process PTHREAD_THREADS_MAX would be exceeded.
[EINVAL]
在系统的搜索路径 /usr/include, /usr/local/include 中搜索这个宏定义:
root@ubuntu:/media/sf_VMshare/test# grep EAGAIN /usr/include/ -rn|grep define
/usr/include/asm-generic/errno.h:22:#define EWOULDBLOCK EAGAIN /* Operation would block */
/usr/include/asm-generic/errno-base.h:15:#define EAGAIN 11 /* Try again */
导致pthread_create返回11的例子:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
int g_count = 0;
void *thread_count(void *arg)
{
g_count++;
return NULL;
}
void *thread_show(void *arg)
{
while (1) {
printf("g_count: %d\n", g_count);
sleep(1);
}
return NULL;
}
int main(int argc, char *argv[])
{
#define CHECK_RET(fun, ret) if (ret != 0) {strcpy(fun_name, #fun); goto done;}
char fun_name[256] = {0};
int ret;
pthread_t tid;
ret = pthread_create(&tid, NULL, thread_show, NULL);
CHECK_RET(pthread_create, ret);
while(1) {
ret = pthread_create(&tid, NULL, thread_count, NULL);
CHECK_RET(pthread_create, ret);
}
done:
printf("%s ret: %d, g_count: %d\n", fun_name, ret, g_count);
return -1;
#undef CHECK_RET
}
/*
root@ubuntu:/media/sf_VMshare/test# ./a.out
g_count: 212
g_count: 30110
pthread_create ret: 11, g_count: 32682
*/
这个问题解决可用用下面三个办法解决:
- 在子线程中设置
pthread_detach(pthread_self())
, 注意保证主线程在子线程运行结束前不会运行结束或退出; - 在主线程中对对应的子线程调用
pthread_join
, 注意这个是一个阻塞调用,阻塞到子线程运行结束; - 在主线程启动子线程时就设置好属性
pthread_attr_t : PTHREAD_CREATE_DETACHED
,注意点同1;
通过上面三个办法,都不会再有pthread_create返回11的错误了,join或detach可以让OS及时回收对应资源。