线程有许多属性,可以在终端中查看跟线程属性相关的函数:
敲入如下命令后连续按两下tab键
gec@ubuntu:~$ man pthread_attr_
pthread_attr_destroy pthread_attr_getschedpolicy pthread_attr_setaffinity_np pthread_attr_setscope
pthread_attr_getaffinity_np pthread_attr_getscope pthread_attr_setdetachstate pthread_attr_setstack
pthread_attr_getdetachstate pthread_attr_getstack pthread_attr_setguardsize pthread_attr_setstackaddr
pthread_attr_getguardsize pthread_attr_getstackaddr pthread_attr_setinheritsched pthread_attr_setstacksize
pthread_attr_getinheritsched pthread_attr_getstacksize pthread_attr_setschedparam
pthread_attr_getschedparam pthread_attr_init pthread_attr_setschedpolicy
gec@ubuntu:~$
可见,线程的属性多种多样,可以归总为如下表格:
获取属性API功能设置属性API功能pthread_attr_getdetachstate( )获取分离属性pthread_attr_setdetachstate( )设置分离属性pthread_attr_getguardsize( )获取栈警戒区大小pthread_attr_setguardsize( )设置栈警戒区大小pthread_attr_getinheritsched( )获取继承策略pthread_attr_setinheritsched( )设置继承策略pthread_attr_getschedpolicy( )获取调度策略pthread_attr_setschedpolicy( )设置调度策略pthread_attr_getschedparam( )获取调度参数pthread_attr_setschedparam( )设置调度参数pthread_attr_getscope( )获取竞争范围pthread_attr_setscope( )设置竞争范围pthread_attr_getaffinity_np( )获取CPU亲和度pthread_attr_setaffinity_np( )设置CPU亲和度pthread_attr_getstack( )获取栈指针和栈大小pthread_attr_setstack( )设置栈的位置和栈大小pthread_attr_getstacksize( )获取栈大小pthread_attr_setstacksize( )设置栈大小
这些属性可以在创建线程的时候,通过属性变量统一设置,有少部分可以在线程运行之后再进行设置(比如分离属性),下面介绍属性变量如何使用。
由于线程属性众多,因此需要的时候不直接设置,而是先将它们置入一个统一的属性变量中,然后再以此创建线程。属性变量是一种内置数据类型,需要用如下函数接口专门进行初始化和销毁:
#include
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
线程属性的一般使用步骤:
定义且初始化属性变量 attr
将所需的属性,加入 attr 中
使用 attr 启动线程
销毁 attr
示例代码:
#include
#include
#include
#include
#include
#include
void *routine(void *arg __attribute__((unused)))
{
sleep(1);
}
int main()
{
// 初始化属性变量,并将分离属性添加进去
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// 以分离属性启动线程
pthread_t tid;
pthread_create(&tid, &attr, routine, NULL);
// 分离的线程无法接合
if((errno=pthread_join(tid, NULL)) != 0)
perror("接合线程失败");
pthread_exit(NULL);
}
默认情况下,线程启动后处于可接合状态(即未分离),此时的线程可以在退出时让其他线程接合以便释放资源,但若其他线程未及时调用 pthread_join() 去接合它,它将成为僵尸线程,浪费系统资源。
僵尸线程
因此,若线程退出时无需汇报其退出值,则一般要设置为分离状态,处于分离状态下的线程在退出之后,会自动释放其占用的系统资源。
将线程设置为分离状态有两种方式:
在线程启动前,使用分离属性启动线程
在线程启动后,使用 pthread_detach() 强制分离
在线程启动前,使用分离属性启动线程做法如下:
#include
void *routine(void *arg)
{
// ...
}
int main()
{
// 初始化属性变量,并将分离属性添加进去
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// 以分离属性启动线程
pthread_t tid;
pthread_create(&tid, &attr, routine, NULL);
// ...
}
注意:
分离状态下的线程是无法被接合的。
在线程启动后,使用 pthread_detach() 强制分离的做法如下:
#include
void *routine(void *arg)
{
// 强制将自身设置为分离状态
pthread_detach(pthread_self());
// ...
}
int main()
{
// 启动标准线程
pthread_t tid;
pthread_create(&tid, NULL, routine, NULL);
// ...
}
编写一个程序,让主线程先退出并返回一个值,子线程接合主线程后输出主线程的退出值。
解答:
#include
#include
#include
void *routine(void *arg)
{
// 试图接合主线程,并获取其退出值
void *val;
pthread_t mid = *((pthread_t *)arg);
pthread_join(mid, &val);
printf("%s\n", (char *)val);
}
int main()
{
pthread_t tid;
pthread_t mid = pthread_self();
pthread_create(&tid, NULL, routine, (void *)&mid);
// 退出主线程
pthread_exit("abcd");
}