多核程序设计课件4-Linux多线程编程.ppt
《多核程序设计课件4-Linux多线程编程.ppt》由会员分享,可在线阅读,更多相关《多核程序设计课件4-Linux多线程编程.ppt(56页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第五章第五章 Linux 多线程编程多线程编程浙江大学计算机学院POSIX标准标准POSIX的诞生和的诞生和Unix的发展密不可分的发展密不可分l各厂家对各厂家对Unix的开发各自为政,造成了的开发各自为政,造成了Unix的版本相的版本相当混乱,给软件的可移植性带来很大困难,对当混乱,给软件的可移植性带来很大困难,对Unix的的发展极为不利发展极为不利POSIXl可移植操作系统接口:可移植操作系统接口:Portable Operating System Interfacel电气和电子工程师协会(电气和电子工程师协会(Institute of Electrical and Electronics
2、 Engineers,IEEE)开发)开发l提高提高 UNIX 环境下应用程序的可移植性环境下应用程序的可移植性许多其它的操作系统,例如许多其它的操作系统,例如 Microsoft Windows NT,都支持,都支持 POSIX 标准标准 POSIX 线程库线程库Pthreads介绍介绍IEEE POSIX IEEE POSIX 标准标准 p1003.1c(Pthreads)p1003.1c(Pthreads)定义了处理线程的一系列定义了处理线程的一系列C C 语语言类型的言类型的APIAPI。lPOSIX POSIX 线程线程 是是 线程的线程的 POSIXPOSIX标准,定义了创建和操纵
3、线程的一套标准,定义了创建和操纵线程的一套 APIAPI在在LinuxLinux中,线程一般被认为是中,线程一般被认为是“轻量级的进程轻量级的进程”。Linux Linux 创建进程所使用的函数是创建进程所使用的函数是fork()fork()或者或者vforkvfork()()。而对线程的创。而对线程的创建和管理,建和管理,LinuxLinux可以使用可以使用POSIXPOSIX的线程库的线程库pthreadspthreads提供的提供的APIsAPIs。LinuxLinux提供的多线程和多进程执行环境主要目的是提高系统资源利用提供的多线程和多进程执行环境主要目的是提高系统资源利用率和任务的并
4、发或并行程度。率和任务的并发或并行程度。针对针对WindowsWindows操作系统,操作系统,PthreadsPthreads也存在一个开放源代码的版本,称也存在一个开放源代码的版本,称为为pthreads-win32pthreads-win32 POSIX pthreads库库线程的创建线程的创建POSIX POSIX pthreadspthreads 线程库中提供的创建线程的函数是线程库中提供的创建线程的函数是pthread_createpthread_create()(),函数原型是:,函数原型是:int pthread_create(pthread_t *thread,pthread
5、_attr_t*attr,void*(*start_routine)(void*),void*arg);第一个参数是第一个参数是pthread_tpthread_t 类型的指针,这个指针指向用来存类型的指针,这个指针指向用来存放当线程创建成功后的所创建的线程的标志放当线程创建成功后的所创建的线程的标志 第二个参数表明被创建的线程可以拥有的属性第二个参数表明被创建的线程可以拥有的属性 第三个参数是一函数指针,此函数指针指向线程的实现函数第三个参数是一函数指针,此函数指针指向线程的实现函数第四个参数第四个参数argarg是是void*void*类型的,此参数指向实际线程处理类型的,此参数指向实际线
6、程处理函数执行的时候所需要的参数函数执行的时候所需要的参数 POSIX pthreads库库(续续)线程的退出线程的退出 在线程的处理函数中,可以显式的调用在线程的处理函数中,可以显式的调用pthread_exitpthread_exit()()结束线结束线程执行。程执行。pthread_exitpthread_exit()()函数的函数原型是:函数的函数原型是:void pthread_exit(void*retval);参数是指向线程的返回值参数是指向线程的返回值 线程的退出不能简单使用线程的退出不能简单使用exit()exit()函数,因为一旦使用了函数,因为一旦使用了 exitexit
7、()()函数,实际上是整个进程的退出,会导致其他线程也随着进函数,实际上是整个进程的退出,会导致其他线程也随着进程的消亡而消亡程的消亡而消亡POSIX pthreads库库(续续)等待线程结束等待线程结束 线程创建完毕后,创建线程的线程,就可以使用线程创建完毕后,创建线程的线程,就可以使用pthread_joinpthread_join()()函数等待被创建的线程的结束。函数等待被创建的线程的结束。pthread_joinpthread_join()()函数会挂起创建线程的线程的执行,直到等待函数会挂起创建线程的线程的执行,直到等待到想要等待的子线程。到想要等待的子线程。pthread_joi
8、npthread_join()()函数的函数原型是:函数的函数原型是:int pthread_join(pthread_t th,void*thread_return);第一个参数第一个参数thth是需要等待的线程的标志是需要等待的线程的标志 如果如果thread_returnthread_return不为空,那么不为空,那么thread_returnthread_return指向指向thth返回返回的值的值 调用调用pthread_joinpthread_join()()函数的目的是释放相关内存资源函数的目的是释放相关内存资源POSIX pthreads库库(续续)线程的分离线程的分离 pt
9、hread_joinpthread_join()()函数虽然可以等待被创建的线程的结束,且函数虽然可以等待被创建的线程的结束,且可以回收被创建的线程的相关内存资源,但是这个函数的主要可以回收被创建的线程的相关内存资源,但是这个函数的主要缺点是要挂起调用缺点是要挂起调用pthread_joinpthread_join()()的线程。的线程。POSIXPOSIX线程库提供了一个函数线程库提供了一个函数pthread_detachpthread_detach()(),使得子线程,使得子线程本身自己有自我回收内存资源的能力。本身自己有自我回收内存资源的能力。此函数的原型是:此函数的原型是:int pt
10、hread_detach(pthread_t th);这个函数的目的是让线程这个函数的目的是让线程 thth 可以处于分离可以处于分离(detached)(detached)状态状态 处于分离状态的线程有能力在自己结束执行的时候回收相关处于分离状态的线程有能力在自己结束执行的时候回收相关的内存资源的内存资源 POSIX pthreads库库(续续)获得当前线程标志获得当前线程标志 使用使用pthread_selfpthread_self()()函数可以获得当前线程的标志,函数可以获得当前线程的标志,pthread_selfpthread_self()()的返回值就是当前线程的标志。其函数原型是
11、:的返回值就是当前线程的标志。其函数原型是:lpthread_t pthread_self(void);线程的撤销线程的撤销一个线程可以通过向另个线程发送一个线程可以通过向另个线程发送“请求请求”来结束另一个线程来结束另一个线程的执行。的执行。pthread_cancelpthread_cancel()()函数可以完成这个功能。函数可以完成这个功能。接收撤销请求的线程并不是接收撤销请求的线程并不是“随便随便”就结束了自己的执行,它就结束了自己的执行,它可以忽略、推迟、或者立即响应别的线程发来的结束线程执行可以忽略、推迟、或者立即响应别的线程发来的结束线程执行的请求,这取决于线程设置。的请求,这
12、取决于线程设置。这里的这里的“推迟推迟”是指线程执行到撤销点是指线程执行到撤销点(cancellation point)(cancellation point)的时候,才执行线程的撤销操作。的时候,才执行线程的撤销操作。POSIX pthreadsPOSIX pthreads库中关于撤销操作的函数有:库中关于撤销操作的函数有:lint pthread_setcancelstate(int state,int*oldstate);lint pthread_setcanceltype(int type,int*oldtype);lvoid pthread_testcancel(void);线程的撤
13、销线程的撤销(续续)使用线程撤销相关的操作的例子使用线程撤销相关的操作的例子#include#include#include#include#define THREAD_NUMBER 2static pthread_cond_t cond=PTHREAD_COND_INITIALIZER;static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;pthread_t ptTHREAD_NUMBER;void*thread1(void*arg)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
14、pthread_mutex_lock(&mutex);sleep(5);printf(now thread1 is in cancelation pointn);/*pthread_cond_wait 是一撤销点,是一撤销点,thread1 在这里等待条件变量的满足在这里等待条件变量的满足*/pthread_cond_wait(&cond,&mutex);pthread_mutex_unlock(&mutex);pthread_exit(NULL);线程的撤销线程的撤销(续续)lvoid*thread2(void*arg)ll int i=0;l printf(thread2 sends ca
15、ncelation request to thread1n);l /*向线程向线程 thread1 发送撤销请求发送撤销请求*/l pthread_cancel(pt0);l printf(thread2 endsn);l pthread_exit(NULL);llint main(int argc,char*argv)ll int i;l int ret_val;l ret_val=pthread_create(&pt0,NULL,thread1,NULL);l if(ret_val!=0)l printf(pthread_create error!n);l exit(1);l l ret_
16、val=pthread_create(&pt1,NULL,thread2,NULL);l if(ret_val!=0)l printf(pthread_create error!n);l exit(1);l 线程的撤销线程的撤销(续续)lfor(i=0;i THREAD_NUMBER;i+)l ret_val=pthread_join(pti,NULL);l if(ret_val!=0)l printf(pthread_join error!n);l exit(1);l l l pthread_mutex_destroy(&mutex);l pthread_cond_destroy(&cond
17、);l return 0;l 程序运行结果:程序运行结果:lthread2 sends cancelation request to thread1lthread2 endslnow thread1 is in cancelation point在撤销线程的时候,可以编写程序让线程进一步进行所谓的在撤销线程的时候,可以编写程序让线程进一步进行所谓的“清理清理”工作,比如已经拥有了某个工作,比如已经拥有了某个 mutexmutex,在清理例程中可以,在清理例程中可以释放这个释放这个 mutexmutex;如果动态分配了内存,那么可以在清理例程;如果动态分配了内存,那么可以在清理例程中释放动态分配
18、的内存。中释放动态分配的内存。使用使用Pthreads编写的程序例子编写的程序例子一个简单的多线程程序一个简单的多线程程序helloworld.chelloworld.c,其创建了两个几乎一样其创建了两个几乎一样的线程的线程l#include l#include l#include l#include l#define THREAD_NUMBER 2lint retval_hello1=2,retval_hello2=3;lvoid*hello1(void*arg)ll char*hello_str=(char*)arg;l sleep(1);l printf(%sn,hello_str);l
19、 pthread_exit(&retval_hello1);llvoid*hello2(void*arg)ll char*hello_str=(char*)arg;l sleep(2);l printf(%sn,hello_str);l pthread_exit(&retval_hello2);l 使用使用Pthreads编写的程序例子编写的程序例子(续续)int main(int argc,char*argv)int i;int ret_val;int*retval_hello2;/*申明申明pthread_t 类型的数组类型的数组 pt 用来存放创建线程得到的线程的标志。这里创建的两个线程
20、,分别传递了不同的参用来存放创建线程得到的线程的标志。这里创建的两个线程,分别传递了不同的参数,分别数,分别arg0 和和 arg1 指向所要传递的字符串起始地址。指向所要传递的字符串起始地址。*/pthread_t ptTHREAD_NUMBER;const char*argTHREAD_NUMBER;arg0=hello world from thread1;arg1=hello world from thread2;printf(Begin to create threads.n);/*使用使用 pthread_create()分别创建了两个线程。创建线程的时候,分别创建了两个线程。创建
21、线程的时候,pthread_create()的第二个参数是的第二个参数是 NULL,表示被创建的线程拥有缺省的属性:被创建的线程是处于可加入状态,且其调度机制是普通的非实时的,表示被创建的线程拥有缺省的属性:被创建的线程是处于可加入状态,且其调度机制是普通的非实时的*/ret_val=pthread_create(&pt0,NULL,hello1,(void*)arg0);if(ret_val!=0)printf(pthread_create error!n);exit(1);ret_val=pthread_create(&pt1,NULL,hello2,(void*)arg1);if(ret
22、_val!=0)printf(pthread_create error!n);exit(1);使用使用Pthreads编写的程序例子编写的程序例子(续续)printf(Now,the main thread returns.n);printf(Begin to wait for threads.n);/*主线程使用主线程使用 pthread_join()等待两个子线程的结束。其中,等待两个子线程的结束。其中,retval_hello0 和和 retval_hello1 分别指向两个线程通过调用分别指向两个线程通过调用 pthread_exit()返回的值。返回的值。*/for(i=0;i TH
23、READ_NUMBER;i+)ret_val=pthread_join(pti,(void*)&retval_helloi);if(ret_val!=0)printf(pthread_join error!n);exit(1);else printf(return value is%dn,*retval_helloi);return 0;在在linuxlinux 中,编译线程相关的程序的时候需要用到中,编译线程相关的程序的时候需要用到libpthreadlibpthread 库。比如要编译库。比如要编译helloworld.chelloworld.c 为可执行程序为可执行程序 hellowor
24、ldhelloworld,那,那么可以这样使用么可以这样使用 gccgcc 来编译:来编译:l#gcc helloworld.c-o helloworld lpthread 线程的属性线程的属性pthread_createpthread_create()()创建线程的时候,如果第二个参数是创建线程的时候,如果第二个参数是NULL NULL 那么使用那么使用缺省的线程属性。线程的属性名和其含义可以在下表中看到缺省的线程属性。线程的属性名和其含义可以在下表中看到v属性名属性名v意意义义v detachstatev选择被创建的线程是处于可加入的状态还是分离状态。可加入状态值是PTHREAD_CREA
25、TE_JOINABLE;分离状态值是PTHREAD_CREATE_DETACHED。缺省状态值是PTHREAD_CREATE_JOINABLE。pthread_attr_setdetachstate()可设置线程为加入或者分离状态;pthread_attr_getdetachstate()可以获得当前线程是否是加入的或者是分离的状态。v schedpolicyv为被创建的线程选择调度策略。被创建的线程的状态可以是SCHED_OTHER(一般的,非实时调度)、SCHED_RR(实时,轮转调度)或者SCHED_FIFO(实时,先进先出调度)。缺省值是SCHED_OTHER。实时调度SCHED_RR
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多核 程序设计 课件 Linux 多线程 编程
限制150内