《多线程编程5.ppt》由会员分享,可在线阅读,更多相关《多线程编程5.ppt(11页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第5章 多线程编程5.1 LINUX5.1 LINUX下线程概述下线程概述5.2 LINUX5.2 LINUX线程实现线程实现1线程概述 进程是系统中程序执行和资源分配的基本单位。每个进程都拥有自己的数据段、代码段和堆栈段,这就造成了进程在进行切换等操作时都需要有比较负责的上下文切换等动作。为了进一步减少上下文切换开销,进程在演变中出现了另一个概念线程。它是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。同进程一样,线程也将相关的变量值放在线程控制表中,一个进程可以有多个线
2、程,也就是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。要注意的是,由于线程共享了进程的资源和地址空间,因此,任何线程对系统资源的操作都会给其他线程带来影响。因此,线程中的同步就是非常重要的问题了。在多线程系统中,线程与进程的关系如下表所示。5.1 LINUX下线程概述进程用户地址空间线程一线程二线程三2多线程编程这里讲的线程相关操作都是用户空间线程的操作。在LINUX中,一般Pthread线程库是一套通用的线程库,是由POSIX提出的,因此具有很好的可移植性。1线程创建和退出(1)函数说明 创建函数实际上是确定调用该线程函数的入口点,这里通常使用的函数是pthread_create
3、。在线程创建以后,就开始运行相关的线程函数,在该函数运行完了后,该线程也就退出了,这也是线程退出的一种方法。另一种退出线程的方法是使用函数pthread_exit,这是线程的主动行为。这里要注意的是,在使用线程函数时,不能随意使用exit退出函数进行出错处理,由于exit的作用是使调用进程终止,往往一个进程包含多个线程,因此,在使用exit 之后,该进程中的所有线程都终止了。因此,在线程中就可以使用pthread_exit 来代替进程中的exit。由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放。正如进程之间可以用wait()系
4、统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数,pthread_join可以用于将当前线程挂起,等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。(2)函数格式下表列出了pthread_create函数的语法要点。5.2 LINUX线程实现3多线程编程下表列出了pthread_exit函数的语法要点。5.2 LINUX线程实现所需头文件#include函数原型int pthread_create(pthread_t*thread,pthread_attr_t*attr
5、,void*(*start_routine)(void*),void*arg)函数传入值thread:线程标识符attr:线程属性设置start_routine:线程函数的起始地址arg:传递start_routine的参数函数返回值成功:0出错:-1所需头文件#include函数原型void pthread_exit(void*retval)函数传入值retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join来检索获取。4多线程编程5.2 LINUX线程实现下表列出了pthread_join函数的语法要点。所需头文件#include函数原型int p
6、thread_join(pthread_t th,void*thread_return)函数传入值th:等待线程的标识符thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)函数返回值成功:0出错:-1(3)函数使用以下实例中创建了两个线程,一个是在程序运行到中途时调用pthread_exit函数退出,另一个是正常运行退出。在主程序中收集这两个线程的退出信息,并释放资源,从这个实例中可以看出,这两个线程是并发运行的。5多线程编程#include#include void thread1(void)int i=0;for(i=0;i6;i+)printf(Thi
7、s is a pthread1.n);if(i=2)pthread_exit(0);sleep(1);void thread2(void)int i;for(i=0;i3;i+)printf(This is a pthread2.n);pthread_exit(0);int main(void)pthread_t id1,id2;int i,ret;ret=pthread_create(&id1,NULL,(void*)thread1,NULL);if(ret!=0)printf(Create pthread error!n);exit(1);ret=pthread_create(&id2,N
8、ULL,(void*)thread2,NULL);if(ret!=0)printf(Create pthread error!n);exit(1);pthread_join(id1,NULL);pthread_join(id2,NULL);exit(0);5.2 LINUX线程实现6多线程编程2修改线程属性(1)函数说明大家还记得pthread_create函数的第二个参数线程的属性。在上例中将该值设为NULL,也就是默认属性,线程有多个属性。这些属性主要包括绑定属性、分离属性、堆栈地址、堆栈大小、优先级。其中默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。l 绑定属性L
9、INUX中采用“一对一”的线程机制,也就是一个用户线程对应一个内核线程。绑定属性就是一个用户线程固定的分配给一个内核线程,因为CPU时间片的调度是面向内核线程的,因此具有绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应。而与之对应的非绑定属性就是指用户线程和内核线程的关系不是始终固定的,而是由系统来控制分配的。l分离属性分离属性是用来决定一个线程以什么样的方式来终止自己。在非分离情况下,当一个线程结束时,它所占用的系统资源并没有被释放,也就是没有真正的终止,只有当pthread_join函数返回时,创建的线程才能释放自己占用的系统资源。而在分离属性情况下,一个线程的分离属性,而这个线
10、程运行又非常快,那么它很可能在pthread_create函数返回之前就终止了,它终止以后可能将线程号和系统资源移交给其他的线程使用,这时调用pthread_create的线程就得到了错误的线程号。这些属性的设置都是通过一定的函数来完成的,通常首先调用pthread_attr_init函数进行初始化,之后再调用相应的属性设置函数。设置绑定属性的函数pthread_attr_setscope,设置线程分离函数的属性pthread_attr_setdetachstate,设置线程优先级的相关函数为pthread_attr_getschedparam(获取线程优先级)和pthread_attr_se
11、tschedparam(设置线程优先级)。在设置完这些属性后,就可以调用pthread_create函数来创建线程了。5.2 LINUX线程实现7多线程编程(2)函数格式下表列出了pthread_attr_init函数的语法要点。5.2 LINUX线程实现所需头文件#include函数原型int pthread_attr_init(pthread_attr_t*attr)函数传入值attr:线程属性函数返回值成功:0出错:-1所需头文件#include函数原型Int pthread_attr_setscope(pthread_attr_t*attr,int scope)函数传入值attr:线程
12、属性scopePTHREAD_SCOPE_SYSTEM:绑定PTHREAD_SCOPE_PROCESS:非绑定函数返回值成功:0出错:-1下表列出了pthread_attr_setscope函数的语法要点。8多线程编程5.2 LINUX线程实现所需头文件#include函数原型int pthread_attr_getschedparam(pthread_attr_t*attr,struct sched_param*param)函数传入值attr:线程属性param:线程优先级函数返回值成功:0出错:-1下表列出了pthread_attr_setdetachstate函数的语法要点。所需头文件#
13、include函数原型Int pthread_attr_setdetachstate(pthread_attr_t*attr,int detachstate)函数传入值attr:线程属性detachstatePTHREAD_SCOPE_DETACHED:分离PTHREAD_SCOPE_JOINABLE:非分离函数返回值成功:0出错:-1下表列出了pthread_attr_getschedparam函数的语法要点。9多线程编程5.2 LINUX线程实现下表列出了pthread_attr_setschedparam函数的语法要点。所需头文件#include函数原型int pthread_attr_
14、setschedparam(pthread_attr_t*attr,struct sched_param*param)函数传入值attr:线程属性param:线程优先级函数返回值成功:0出错:-110多线程编程3使用实例该实例将上个实例的第一个线程设置为分离属性,并将第二个线程设置为始终运行状态,这样就可以在第二个线程运行过程中查看内存值的变化。5.2 LINUX线程实现#include#include#include void thread1(void)int i=0;for(i=0;i6;i+)printf(This is a pthread1.n);if(i=2)pthread_exit
15、(0);sleep(1);void thread2(void)int i;while(1)for(i=0;i3;i+)printf(This is a pthread2.n);sleep(1);pthread_exit(0);int main(void)pthread_t id1,id2;int i,ret;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_D
16、ETACHED);ret=pthread_create(&id1,&attr,(void*)thread1,NULL);if(ret!=0)printf(Create pthread error!n);exit(1);ret=pthread_create(&id2,NULL,(void*)thread2,NULL);if(ret!=0)printf(Create pthread error!n);exit(1);pthread_join(id2,NULL);return(0);接下来可以在线程一运行前后使用“free”命令查看内存使用情况。可以看到,线程一在运行结束后就收回了系统资源,释放了内存。11多线程编程