目录
pthread_detach
参数pthread
返回值
测试代码1
测试结果
pthread_attr_init
参数attr
返回值
pthread_attr_destroy
参数attr
返回值
pthread_attr_setdetachstate
参数attr
参数detachstate
返回值
测试代码2
测试结果
线程使用注意事项
pthread_detach
实现线程分离。线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。
man 3 pthread_detach
参数pthread
待分离的线程ID。
返回值
成功:0
失败:错误号
测试代码1
分离一个线程,并回收。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
void *HuiDiao_HanShu(void *arg)
{
printf("这是子线程的回调函数,子线程的进程ID是%d,子线程ID是%lu。\n", getpid(), pthread_self());
return (void *)0;
}
int main(int argc, char *argv[])
{
int flag;
pthread_t ZiXianCheng_ID; //子线程ID
void *num = NULL;
flag = pthread_create(&ZiXianCheng_ID, NULL, HuiDiao_HanShu, NULL); //创建子线程
if (flag != 0)
{
printf("创建子线程错误:%s\n", strerror(flag));
exit(1);
}
printf("这是主线程,进程ID是%d,线程ID是%lu。\n", getpid(), pthread_self());
printf("开始分离子线程!\n");
flag = pthread_detach(ZiXianCheng_ID);
if (flag != 0)
{
printf("分离子线程错误:%s\n", strerror(flag));
exit(1);
}
printf("分离子线程完成!\n");
printf("这是主线程,先睡一会,再回收子线程!\n");
sleep(1);
printf("这是主线程,睡醒了!\n");
printf("开始回收子线程!\n");
flag = pthread_join(ZiXianCheng_ID, &num);
if (flag != 0)
{
printf("回收子线程错误:%s\n", strerror(flag));
exit(1);
}
printf("回收子线程完成!\n");
printf("num=%d\n", (int)num);
pthread_exit(NULL);
return 0;
}
测试结果
分离后的子线程结束后,会自动清理PCB,无需回收。
pthread_attr_init
初始化线程属性。
man 3 pthread_attr_init
参数attr
传出参数的属性。
返回值
成功:0
失败:错误号
pthread_attr_destroy
销毁线程属性所占用的资源。
man 3 pthread_attr_destroy
参数attr
传出参数的属性。
返回值
成功:0
失败:错误号
pthread_attr_setdetachstate
设置线程属性。
man 3 pthread_attr_setdetachstate
参数attr
已初始化的线程属性。
参数detachstate
分离线程:PTHREAD_CREATE_DETACHED
非分离线程:PTHREAD _CREATE_JOINABLE
返回值
成功:0
失败:错误号
测试代码2
设置线程的属性为分离属性,再回收子进程。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
void *HuiDiao_HanShu(void *arg)
{
printf("这是子线程的回调函数,子线程的进程ID是%d,子线程ID是%lu。\n", getpid(), pthread_self());
return (void *)0;
}
int main(int argc, char *argv[])
{
int flag;
pthread_t ZiXianCheng_ID; //子线程ID
pthread_attr_t XianCheng_ShuXing; //线程属性
void *num = NULL;
flag = pthread_attr_init(&XianCheng_ShuXing); //初始化线程属性
if (flag != 0)
{
printf("线程属性初始化错误:%s\n", strerror(flag));
exit(1);
}
flag = pthread_attr_setdetachstate(&XianCheng_ShuXing, PTHREAD_CREATE_DETACHED); //设置线程属性为分离属性
if (flag != 0)
{
printf("设置线程属性错误:%s\n", strerror(flag));
exit(1);
}
flag = pthread_create(&ZiXianCheng_ID, &XianCheng_ShuXing, HuiDiao_HanShu, NULL); //创建子线程,借助线程属性将子进程分离
if (flag != 0)
{
printf("创建子线程错误:%s\n", strerror(flag));
exit(1);
}
flag = pthread_attr_destroy(&XianCheng_ShuXing); //销毁线程属性
if (flag != 0)
{
printf("线程属性销毁错误:%s\n", strerror(flag));
exit(1);
}
printf("这是主线程,进程ID是%d,线程ID是%lu。\n", getpid(), pthread_self());
printf("这是主线程,先睡一会,再回收子线程!\n");
sleep(1);
printf("这是主线程,睡醒了!\n");
printf("开始回收子线程!\n");
flag = pthread_join(ZiXianCheng_ID, &num);
if (flag != 0)
{
printf("回收子线程错误:%s\n", strerror(flag));
exit(1);
}
printf("回收子线程完成!\n");
printf("num=%d\n", (int)num);
pthread_exit(NULL);
return 0;
}
测试结果
说明子线程已被成功分离,无需回收。
线程使用注意事项
主线程退出其他线程不退出,主线程应调用 pthread_exit。
避免僵尸线程,被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值。
malloc和mmap申请的内存可以被其他线程释放。
应避免在多线程模型中调用fork除非马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均 pthread_exit。
信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制。