Linux 多线程编程

概念原来指向main()的线程叫做主线程(main thread)使用pthread_create()创建出来的线程,叫做子线程(child thread)主/子线程只有在创建时才有区别, 创建完了就一视同仁, 都是一样的独立个体, 可以有交流、共享和私有, 但没有上下级, 这一点和多进程一样, 只有在创建的瞬间才有parent process 和child process 的区别, 创建完了就都是一样的独立个体创建完子线程之后,两个线程之间独立运行,线程的执行先后次序由os的调度算法决定线程之间相互独立也相互影响,因为主线程结束时,会导致进程结束,进程结束时,会导致该进程的所有线程结束多个线程共享一个进程, 而一个进程只有一个输出终端, so一定要调度好, 要不有的线程输出会看不到, 最low的做法就是sleep()一下保证线程可以执行完
模型$gcc -pthread#includepthread_self()/pthread_equal() //获得threadidpthread_attr_init()/pthread_attr_setdetachstate()/… //创建一个线程前设置 pthread_create() //创建一个线程 pthread_detach()pthread_setcancelstate()/pthread_setcanceltype() //已有一个线程后设置 pthread_kill() //向线程发送一个信号 pthread_exit() //退出线程但不退出进程 pthread_cancel() //终止另一个线程 pthread_join() //等待一个线程 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_param schedparam; //线程的调度参数 int inheritsched; //线程的继承性 int scope; //线程的作用域 size_t guardsize; //线程栈末尾的警戒缓冲区大小 int stackaddr_set; //线程的栈设置 void * stackaddr; //线程栈的位置 size_t stacksize; //线程栈的大小}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\n); //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()) ,这个函数只支持传递void*型的型参,实际使用需要另外定义一个目标类型的指针,将arg强制类型转换后得到正确的类型
pthread_detach()//将thread表示的线程标记为detached,当一个detached的线程结束后,它占用的资源被自动释放,其他线程也不能用pthread_join()等待//detach一个已经被detach了的线程将导致不确定的结果//成功返回0,失败返回error numberint pthread_detach(pthread_t thread);pthread_setcancelstate()//设置当前线程是否允许被cancel,成功返回0,失败返回error number int pthread_setcancelstate(int state, int *oldstate);state:设置新状态
pthread_cancel_enable //允许取消pthread_cancel_disable //不允许取消\oldstate:用于带出设置之前的旧状态
pthread_setcanceltype()//设置可取消性的类型,即当前线程何时被取消 //成功返回0,失败返回error number int pthread_setcanceltype(int type, int *oldtype);type:设置新类型
pthread_cancel_defered //延迟取消pthread_cancel_asynchronous //立即取消oldtype:用于带出设置之前的旧类型
pthread_exit()//结束调用线程并返回一个retval值,这个值可以被同进程中的其他线程通过pthread_join()来读取,当然,前提条件是当前线程可以被汇合/等待void pthread_exit(void *retval);线程的3种终止方式:简单的从启动例程中返回,返回值是线程的退出码线程可以被同一进程中的其他线程取消线程调用pthread_exit()pthread_cancel()//发送一个结束请求给一个线程,是否取消以及何时取消取决于线程的属性:state和type//成功返回0,失败返回error numberint pthread_cancel(pthread_t thread);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#include#include#include //strerror()//没有这个.h会把strerror(error)当intvoid* calc(void* pv){ printf(primeter is %lg, area is:%lg\n,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\n); scanf(%d,piradius); pthread_t thread; int error=pthread_create(&thread,null,calc,(void*)piradius); if(0!=error) printf(%s\n,strerror(error)),exit(-1); error=pthread_join(thread,null); if(0!=error) printf(%s\n,strerror(error)),exit(-1); free(piradius); piradius=null; return 0;} //03join.c 使用pthread_join获取目标线程的退出状态#include#include#include#includevoid* task(void* pv){ char* pc=hello; return (void*)pc;}main(){ //创建子线程,使用pthread_create pthread_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\n,strerror(error)),exit(-1); printf(child thread returned:%s\n,ps); return 0;} //使用pthread_create()创建新线程#include#include#include#includevoid* 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\n); else printf(these two are unequal\n); int i=0; for(i=0;i<10;i++){ printf(i am the new thread\n); 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\n,strerror(errno)),exit(-1); sleep(10); printf(child thread's id:%lu,parent thread's id:%lu\n,thread,pthread_self());//pthread_self(),获取当前线程自己的线程编号 return 0;}//使用pthread_create()创建子线程,在线程处理函数中计算1~100之间的和,保存在sum中,返回该变量的地址,主线程等待子线程结束,并获取退出状态信息,并打印#include#include#include#includevoid* sum(void* pv){ int i=0,sum=0; for(i=1;i<=100;i++) sum+=i; printf(%d\n,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\n,strerror(res)),exit(-1); printf(child thread return : %s\n,retval); return 0;}//在线程处理函数中打印1~20之间的函数,当打印到10时终止当前进程并带出10,主线程等待并获取退出状态信息,打印最终结果#include#includevoid* task(void* pv){ static int i=0; for(i=1;i<=20;i++){ if(10==i) pthread_exit((void*)&i); //pthread_exit() vs exit() else printf(i=%d\n,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\n,*retval); return 0;}//使用pthread_cancel()取消指定的线程#include#include#includevoid* task(void* pv){ pthread_setcancelstate(pthread_cancel_disable,null); //设置该线程不可取消 while(1){ printf(i am superman\n); sleep(1); } return null;}void* task2(void* pv){ printf(cancelling thread...\n); sleep(2); pthread_cancel(*(pthread_t*)pv); printf(cancelling successfully\n);}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*/

13种功率半导体器件介绍
台积电扩大与大陆集成电路产业化基地和技术中心合作
极低功耗的物联网唤醒芯片
基于SolidWorks的开关柜模型的热传导结构
TCL聚焦主业,华星光电OLED试验线已开始产品试制
Linux 多线程编程
Linux文件权限及Makefile
最小尺寸CAT1 模组(17.7mmx15.8mm)的: CLM920_YV9 (ASR 1603 兼容2G封装 )
数字货币支付方式将成为记账方式之一
用于人体暴露评估5G信号的电磁场(EMF)设计
冰箱温度调节怎么调节?冰箱温控器接线图
节能LED显示屏是如何设计的
区块链存在的价值是什么
新唐科技N76E003单片机简介
一种掉电保护原理电路
跨阻放大器对光信号的要求
解读μLED新兴介质的起源、技术突破以及发展前景
瑞芯微RK3399将全面助力推动政企办公设备国产化
英创信息技术WEC7与WEC2013介绍
在实际生活中,量子物理有用吗?