概念
- 原来指向main()的线程叫做主线程(main thread)
- 使用pthread_create()创建出来的线程,叫做子线程(child thread)
- 主/子线程只有在创建时才有区别, 创建完了就一视同仁, 都是一样的独立个体, 可以有交流、共享和私有, 但没有上下级, 这一点和多进程一样, 只有在创建的瞬间才有parent process 和child process 的区别, 创建完了就都是一样的独立个体
- 创建完子线程之后,两个线程之间独立运行,线程的执行先后次序由OS的调度算法决定
- 线程之间相互独立也相互影响,因为主线程结束时,会导致进程结束,进程结束时,会导致该进程的所有线程结束
- 多个线程共享一个进程, 而一个进程只有一个输出终端, So一定要调度好, 要不有的线程输出会看不到, 最low的做法就是sleep()一下保证线程可以执行完
模型
- 获得ThreadID :pthread_self()/pthread_equal()
- 创建一个线程前设置 :pthread_attr_init()/pthread_attr_setdetachstate()/…
- 创建一个线程 :pthread_create()
- 已有一个线程后设置 :pthread_detach()pthread_setcancelstate()/pthread_setcanceltype()
- 向线程发送一个信号 :pthread_kill()
- 退出线程但不退出进程 :pthread_exit()
- 终止另一个线程 :pthread_cancel()
- 等待一个线程 :pthread_join()
- $gcc -pthread
头文件
#include<pthread.h>pthread_self()
//返回调用线程的IDpthread_t pthread_self(void);pthread_equal()
//对比两个线程ID,相等返回非0,不等返回0int pthread_equal(pthread_t t1, pthread_t t2);pthread_attr_init()/ pthread_attr_destroy()
//pthread_attr_init()初始化一个线程属性对象attr,不指定attr就按默认参数进行初始化。//pthread_attr_destroy()销毁一个线程属性对象,销毁的操作对使用这个attr的线程有影响//成功返回0,失败返回error numberint pthread_attr_init(pthread_attr_t *attr);int pthread_attr_destroy(pthread_attr_t *attr);更改attr对象的函数
//成功返回0,失败返回error numbertypedef struct{int detachstate;//线程的分离状态 int schedpolicy;//线程调度策略struct sched_paramschedparam; //线程的调度参数int inheritsched; //线程的继承性int scope;//线程的作用域size_tguardsize;//线程栈末尾的警戒缓冲区大小int stackaddr_set;//线程的栈设置void *stackaddr;//线程栈的位置size_tstacksize;//线程栈的大小}pthread_attr_t;pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate)pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate)PTHREAD_CREATE_JOINABLE / PTHREAD_CREAT_DETACHEDint detachstate;pthread_attr_getdetachstate(&attr,&detachstate);if(PTHREAD_CREATE_JOINABLE==detachstate)printf("1.PTHREAD_CREATE_JOINABLE
");//defaultpthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);SCHED_OTHER / SCHED_FIFO/ SCHED_RRpthread_attr_setsschedchedparam(pthread_attr_t *attr, const struct sched_param *param);pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);struct sched_param {int sched_priority;// Scheduling priority,int sched_get_priority_max/sched_get_priority_min (int policy)};pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);PTHREAD_INHERIT_SCHED /PTHREAD_EXPLICIT_SCHEDpthread_attr_setscope(pthread_attr_t *attr, int scope);pthread_attr_getscope(const pthread_attr_t *attr, int *scope);PTHREAD_SCOPE_SYSTEM/ PTHREAD_SCOPE_PROCESSpthread_attr_setguardsize ( pthread_attr_t *attr, size_t guardsize );pthread_attr_getguardsize ( const pthread_attr_t *attr, size_t *guardsize );>0/ 0(默认1 page,当然还可以指定任意值)pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);pthread_attr_setstacksize ( pthread_attr_t *attr, size_t size );pthread_attr_getstacksize ( const pthread_attr_t *attr, size_t *size );pthread_create()
//这个函数的create有‘e’ //p代表POSIX//在调用进程中创建一个新的线程,新的线程通过激活start_routine()来开始执行,arg是start_routine()唯一的参数//成功返回0,失败返回error numberint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);thread:存放新线程的ID到该参数所指向的缓冲区中, pthread_t是unsigned long int
attr: 线程的属性, 给NULL表示默认方式
start_routine:指定新线程的处理函数,也就是新线程启动之后需要执行的代码,线程处理函数执行完毕之后, 新线程终止
arg: 用于给start_routine传递实参(VS on_exit())
pthread_detach()
//将thread表示的线程标记为detached,当一个detached的线程结束后,它占用的资源被自动释放,其他线程也不能用pthread_join()等待//detach一个已经被detach了的线程将导致不确定的结果//成功返回0,失败返回error numberint pthread_detach(pthread_t thread);pthread_setcancelstate()
//设置当前线程是否允许被cancel,成功返回0,失败返回error numberint pthread_setcancelstate(int state, int *oldstate);state:设置新状态
- PTHREAD_CANCEL_ENABLE //允许取消
- PTHREAD_CANCEL_DISABLE //不允许取消
oldstate:用于带出设置之前的旧状态
pthread_setcanceltype()
//设置可取消性的类型,即当前线程何时被取消//成功返回0,失败返回error numberint pthread_setcanceltype(int type, int *oldtype);type:设置新类型
- PTHREAD_CANCEL_DEFERED //延迟取消
- PTHREAD_CANCEL_ASYNCHRONOUS //立即取消
oldtype:用于带出设置之前的旧类型
pthread_exit()
//结束调用线程并返回一个retval值,这个值可以被同进程中的其他线程通过pthread_join()来读取,当然,前提条件是当前线程可以被汇合/等待void pthread_exit(void *retval);pthread_cancel()
//发送一个结束请求给一个线程,是否取消以及何时取消取决于线程的属性:state和type//成功返回0,失败返回error numberint pthread_cancel(pthread_t thread);进程的7种终止方式:
正常终止:
- 从 main 返回
- 调用 exit() / _exit() / _Exit()
- 最后一个线程从其启动例程返回
- 最后一个线程调用pthread_exit
异常终止:
- 调用abort()
pthread_join()
//等待thread指定的线程终止,如果目标线程没有终止,则当前线程进入阻塞状态,当目标线程终止时,该函数立即返回,前提:目标线程可以被汇合/等待//如果调用pthread_join()的线程被cancel了,目标线程互保持joinable(不会被撤销)//如果多个线程同时join一个线程,那么结果是不确定的//成功返回0,失败返回error numberint pthread_join(pthread_t thread, void **retval);thread:线程编号
retval:二级指针的返回值
retval- 不是NULL,将拷贝目标线程的状态信息到*retval
- 如果目标线程被cancel了,则将PTHREAD_CANCELED防止在*retval
例子
//02join.c, 使用pthread_join等待目标线程结束#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<string.h>//strerror()//没有这个.h会把strerror(error)当intvoid* Calc(void* pv){printf("primeter is %lg, area is:%lg
",2*3.14**(int*)pv,3.14**(int*)pv**(int*)pv);return NULL;//要求有返回值,所以返回NULL}main(){int* piRadius=(int*)malloc(sizeof(int));printf("please input radius
");scanf("%d",piRadius);pthread_t thread;int error=pthread_create(&thread,NULL,Calc,(void*)piRadius);if(0!=error)printf("%s
",strerror(error)),exit(-1);error=pthread_join(thread,NULL);if(0!=error)printf("%s
",strerror(error)),exit(-1);free(piRadius);piRadius=NULL;return 0;} //03join.c使用pthread_join获取目标线程的退出状态#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>void* task(void* pv){char* pc="hello";return (void*)pc;}main(){//创建子线程,使用pthread_createpthread_t thread;int error=pthread_create(&thread,NULL,task,NULL);if(0!=error)printf("%s",strerror(error)),exit(-1);//等待子线程结束,并获取退出状态信息char* ps=NULL;error=pthread_join(thread,(void**)&ps);if(0!=error)printf("pthread_join %s
",strerror(error)),exit(-1);printf("child thread returned:%s
",ps);return 0;} //使用pthread_create()创建新线程#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>void* task(void* pv){ //需要一个实参,我们又不需要,就可以给个NULL//判断thread中的线程ID是否与pthread_self()的线程ID相等int res=pthread_equal(*(pthread_t*)pv,pthread_self());if(0!=res)printf("these two are Equal
");elseprintf("these two are Unequal
");int i=0;for(i=0;i<10;i++){printf("I am the new thread
");sleep(1);}}int main(){//1.准备存储线程编号的变量pthread_t thread;//2.创建新线程,使用pthread_create()int errno=pthread_create(&thread,NULL,task,(void*)&thread);//子线程执行完task()就结束了,使用arg把thread传入子线程if(0!=errno)printf("pthread_create:%s
",strerror(errno)),exit(-1);sleep(10);printf("child thread"s ID:%lu,parent thread"s ID:%lu
",thread,pthread_self());//pthread_self(),获取当前线程自己的线程编号return 0;}//使用pthread_create()创建子线程,在线程处理函数中计算1~100之间的和,保存在sum中,返回该变量的地址,主线程等待子线程结束,并获取退出状态信息,并打印#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>void* Sum(void* pv){int i=0,sum=0;for(i=1;i<=100;i++)sum+=i;printf("%d
",sum);return (void*)"success";//其实return "success"就行}int main(){pthread_t thread;int res=pthread_create(&thread,NULL,Sum,NULL);if(0!=res)printf("%s",strerror(res)),exit(-1);char *retval=NULL;res=pthread_join(thread,(void**)&retval);if(0!=res)printf("%s
",strerror(res)),exit(-1);printf("child thread return : %s
",retval);return 0;}//在线程处理函数中打印1~20之间的函数,当打印到10时终止当前进程并带出10,主线程等待并获取退出状态信息,打印最终结果#include<stdio.h>#include<pthread.h>void* task(void* pv){static int i=0;for(i=1;i<=20;i++){if(10==i)pthread_exit((void*)&i);//pthread_exit()VSexit()elseprintf("i=%d
",i);}return NULL;}main(){pthread_t thread;pthread_create(&thread,NULL,task,NULL);int *retval=NULL;pthread_join(thread,(void**)&retval); //没有错误处理printf("task returned:%d
",*retval);return 0;}//使用pthread_cancel()取消指定的线程#include<stdio.h>#include<stdlib.h>#include<pthread.h>void* task(void* pv){pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//设置该线程不可取消while(1){printf("I am superman
");sleep(1);}return NULL;}void* task2(void* pv){printf("Cancelling thread...
");sleep(2);pthread_cancel(*(pthread_t*)pv);printf("cancelling successfully
");}main(){pthread_t thread;pthread_t thread2;pthread_create(&thread,NULL,task,NULL);pthread_create(&thread2,NULL,task2,(void*)&thread); pthread_join(thread,NULL);pthread_join(thread2,NULL);return 0;}/*I am supermanI am supermanCancelling thread...I am supermancancelling successfullyI am superman //取消失败了, 说明设置禁止取消成功了I am superman*/本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-10/135942.htm