线程属性 - 线程连接和分离
概述
pthread_join函数阻塞主线程直到指定的线程终止。“连接”是一种在线程间完成同步的方法。
pthread_detach函数可以显式用于分离线程。
使用pthread_create的attr参数可以显式的创建可连接或分离的线程,典型四步如下:
1. 声明一个pthread_attr_t数据类型的线程属性变量
2. 用pthread_attr_init初始化改属性变量
3. 用pthread_attr_setdetachstate设置可分离状态属性
4. 完了后,用pthread_attr_destroy释放属性所占用的库资源
函数用法
创建线程:pthread_creade
int pthread_create(pthread_t * thread,
const pthread_attr_t * attr,
void * (*start_routine)(void *),
void *arg);
参数:
thread - 指向线程的指针。
attr - 指向线程属性的指针。可设置为NULL。
start_routine - 用于线程化的函数指针。
arg - 指向函数参数的指针。
返回值:线程标识id
退出线程:pthread_exit
void pthread_exit(void *retval);
参数:
retval - 指向线程返回值的指针。
获取调用的线程号:pthread_self
pthread_t pthread_self(void);
返回调用线程标识号,返回类型为pthread_t
比较线程标识号:thread_equal
int pthread_equal(pthread_t t1, pthread_t t2);
//返回两个线程标识号是否相等
一次初始化:pthread_once
在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。
在多线程编程环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
线程取消:pthread_cancel
pthread_cancel调用并不等待线程终止,它只提出请求。线程在取消请求(pthread_cancel)发出后会继续运行
int pthread_cancel(pthread_t thread);
发送sig信号:pthread_kill
/*
pthread_kill并不是结束进程的意思,而是向指定ID的线程发送一个信号,只是大部分信号的默认动作是终止进程的运行。
如果线程不处理该信号,则按照信号默认的行为作用于整个进程。信号值0为保留信号,作用是根据函数的返回值判断线程是不是还活着。
pthread_kill的返回值:成功(0) 线程不存在(ESRCH) 信号不合法(EINVAL)
*/
int pthread_kill(pthread_t thread,int sig);
主线程挂起直至目标进程返回:pthread_join
int pthread_join(pthread_t thread, void **retval);
参数:
thread - 线程id,标识唯一线程。
retval - 用户定义的指针,用来存储被等待线程的返回值。
返回值:0代表成功。若失败,返回的则是错误号。
线程分离:pthread_detach
/*
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
通常情况下,若创建一个线程不关心它的返回值,也不想使用pthread_join来回收资源(调用pthread_join的进程会阻塞),就可以使用pthread_detach,将该线程的状态设置为分离态,使线程结束后,立即被系统回收。
主线程退出了,“分离线程”还是一样退出。只是“分离线程”的资源是有系统回收的。
*/
int pthread_detach(pthread_t tid);
//pthread_t tid: 分离线程的tid
//返回值:成功返回0,失败返回错误号。
初始化属性对象:pthread_attr_init
int pthread_attr_init(pthread_attr_t *attr);
销毁属性对象:pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
参数:
attr - 指向线程属性对象的指针。
返回值:0代表成功。若失败,返回的则是错误号。
设置属性对象的分离状态:pthread_attr_setdetachstate
int pthread_attr_setdetachstate(const pthread_attr_t *attr,
int *detachstate);
参数:
attr - 指向线程属性对象的指针。
detachstate - 设置可分离(PTHREAD_CREATE_DETACHED)或可连接属性(PTHREAD_CREATE_JOINABLE)。
示例代码
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 4
void *Print(void *threadid)
{
printf("Thread %d is running\n", *(int*)threadid);
free(threadid);
threadid = NULL;
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;
int rc, t;
pthread_attr_init(&attr);
//your code here
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//end of your code
for(t=0; t<NUM_THREADS; t++)
{
int* id = (int*)malloc(sizeof(int));
*id = t;
printf("Creating thread %d\n", t);
rc = pthread_create(&thread[t], &attr, Print, (void*)id);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++)
{
//your code here
rc = pthread_join(thread[t], NULL);
//end of your code
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Completed join with thread %d\n", t);
}
pthread_exit(NULL);
}