函数原型:
int pthread_create (pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
示例代码
#include线程的属性设置#include #include void *func(void *arg); //线程函数 int main(int argc, char **argv) { pthread_t thread; //线程ID保存变量 int status = pthread_create(&thread,NULL,func,NULL); //创建线程 if(status != 0) { perror("线程创建失败:"); } while (1) { printf("线程1n"); sleep(1); } return 0; } //线程函数 void *func(void *arg) { while(1) { printf("线程2n"); sleep(1); } }
分离属性
一个线程结束时会立即释放它所占有的系统资源。
如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就结束了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。
结合属性(非分离状态)
一条线程如果是可接合的,意味着这条线程在退出时不会自动释放自身资源,而会成为僵尸线程,同时意味着该线程的退出值可以被其他线程获取,只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
线程的默认属性是非分离状态
轻进程 :
轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。
非绑定状态
默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。
绑定状态
绑定状况下,则顾名思义,即某个线程固定的"绑"在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。
函数原型:
int pthread_attr_init(pthread_attr_t *attr);
功 能:
初始化线程属性
参 数:
attr :属性变量
返 回:
失败:errno(错误码)
成功:0
函数原型:
int pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);
功 能:
设置线程的分离属性或结合属性
参 数:
attr :属性变量
detachstate :
PTHREAD_CREATE_DETACHED : 分离属性
PTHREAD_CREATE_JOINABLE : 接合属性
返 回:
失败:errno(错误码)
成功:0
函数原型:
int pthread_join(pthread_t thread, void **retval)
功 能:
获取线程函数的返回值,并释放线程的资源
参 数:
thread:被连接线程的线程号(ID)
retval:指向一个指向被连接线程的返回码的指针的指针(线程返回的地址)
返 回:
失败:errno(错误码)
成功:0
注意
1、当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。
2、被释放的内存空间仅仅是系统空间,你必须手动清除程序分配的空间,比如 malloc() 分配的空间(堆空间)。
3、一个线程只能被一个线程所连接。
示例代码
#include#include #include void *func(void *arg); //线程函数 int main(int argc, char **argv) { pthread_attr_t attr; //定义属性变量 pthread_attr_init(&attr); //初始化属性变量 int status = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED ); //设置属性(分离) // int status = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); //设置属性(结合) if(status != 0) { perror("属性设置失败:"); } pthread_t thread; //线程ID保存变量 status = pthread_create(&thread,&attr,func,NULL); //创建线程 if(status != 0) { perror("线程创建失败:"); } //结合线程(只在线程属性为结合时可以用,NULL表示不接收线程返回的地址) //线程不结束将会一直堵塞在这 pthread_join(thread, NULL); printf("线程结束了n"); return 0; } //线程函数 void *func(void *arg) { for(int i = 0; i < 3; i++) { printf("i = %dn",i); sleep(1); } return NULL; }
为分离属性时的结果
为结合属性时的结果(pthread_join堵塞等待线程结束)
函数原型:
void pthread_exit(void *retval);
功 能:
退出线程
参 数:
retval:线程退出值(返回值地址)
注意
1、pthread_exit():只退出当前子线程。注意:在主线程退出时,其它线程不会结束。
2、pthread_exit退出的线程也需要调用pthread_join去回收子线程的资源
3、在任何一个线程中调用exit函数都会导致进程结束。进程一旦结束,那么进程中的所有线程
都将结束。
函数原型:
int pthread_cancel(pthread_t thread);
功 能:
给指定线程发送一个取消请求
参 数:
thread:线程号(ID)
返 回:
失败:errno(错误码)
成功:0
注意
1、线程收到一个取消请求时,他将会如何表现取决于两个东西:一是当前的取消状态,二是当前的取消类型
2、默认取消状态是 PTHREAD_CANCEL_ENABLE,使能(接受)取消请求默认取消类型是 PTHREAD_CANCEL_DEFERRED,延时响应
函数原型:
int pthread_setcancelstate(int state, int *oldstate);
功 能:
设置线程的取消状态
参 数:
state:
PTHREAD_CANCEL_ENABLE:使能取消请求,表示线程可以接受取消请求
PTHREAD_CANCEL_DISABLE:关闭取消请求,表示关闭取消请求,不对其响应
oldstate :旧的取消状态(一般写NULL)
返 回:
失败:errno(错误码)
成功:0
函数原型:
int pthread_setcancelstate(int state, int *oldstate);
功 能:
设置线程的取消类型
参 数:
type:
PTHREAD_CANCEL_DEFERRED:延时响应(执行完当前任务之后响应)
PTHREAD_CANCEL_ASYNCHRONOUS:立即响应
oldtype:旧的取消类型(一般写NULL)
返 回:
失败:errno(错误码)
成功:0
函数原型:
int pthread_detach(pthread_t thread);
功 能:
设置线程分离属性(可以需要的线程自己设置)
参 数:
thread:线程号(ID)
返 回:
失败:errno(错误码)
成功:0
函数原型:
pthread_t pthread_self(void);
功 能:
获取自己的线程ID号
返 回:
当前线程的ID
示例代码
#include#include #include void *func1(void *arg); //线程函数1 void *func2(void *arg); //线程函数2 int main(int argc, char **argv) { pthread_attr_t attr; //定义属性变量 pthread_attr_init(&attr); //初始化属性变量 int status = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED ); //设置属性(分离) if(status != 0) { perror("属性设置失败:"); } pthread_t thread[3]; //线程ID保存变量 status = pthread_create((thread+0),&attr,func1,NULL); //创建线程(并设置分离属性) if(status != 0) { perror("线程1创建失败:"); } status = pthread_create((thread+1),NULL,func2,NULL); //创建线程(不设置属性默认属性) if(status != 0) { perror("线程2创建失败:"); } pthread_cancel(thread[0]); //给线程1发送取消请求 pthread_cancel(thread[1]); //给线程2发送取消请求 // pthread_join(thread[1], NULL); //结合线程 printf("线程结束了n"); pthread_exit(NULL); //结束主线程但不影响其他线程 // return 0; //整个进程都结束(所有线程结束) } //线程函数1 void *func1(void *arg) { unsigned long int i = 0; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//使能取消请求 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);//设置取消类型(延时取消请求) while(1) { i++; if(i == 0xffffffff) { printf("i = %ldn",i); sleep(1); } } pthread_exit(NULL); } //线程函数2 void *func2(void *arg) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消请求 for(int k = 0; k < 4; k++) { printf("k = %dn",k); sleep(1); if(k == 2) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//使能取消请求 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);//设置取消类型(立即响应取消请求) } } pthread_exit(NULL); }
结果:
可以看出使用pthread_exiit结束主线程其他线程并不会结束
设置取消类型(延时取消请求)线程会执行完当前任务在响应取消请求(可以看i的输出的位置)
关闭取消请求后再开启取消请求,取消请求会立即响应(设置了立即响应)



