Linux多线程设计

上传人:m**** 文档编号:508124526 上传时间:2023-12-17 格式:DOC 页数:17 大小:50.50KB
返回 下载 相关 举报
Linux多线程设计_第1页
第1页 / 共17页
Linux多线程设计_第2页
第2页 / 共17页
Linux多线程设计_第3页
第3页 / 共17页
Linux多线程设计_第4页
第4页 / 共17页
Linux多线程设计_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《Linux多线程设计》由会员分享,可在线阅读,更多相关《Linux多线程设计(17页珍藏版)》请在金锄头文库上搜索。

1、-Linu*多线程设计整理自百科名片。为了方便阅读进展了重新排版。感谢*knuth , he*inbin,fqp19852003等的奉献。原文:baike.baidu./view/400319.htm简介:Linu*多线程设计是指基于Linu*操作系统下的多线程设计,包括多任务程序的设计,并发程序设计,网络程序设计,数据共享等。Linu*系统下的多线程遵循POSI*线程接口,称为pthread。编写Linu*下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。1. 引言线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80

2、年代中期,solaris是这方面的佼佼者。传统的Uni*也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT,当然,也包括Linu*。为什么有了进程的概念后,还要再引入线程呢.使用多线程到底有哪些好处.什么的系统应该选用多线程.我们首先必须答复这些问题。使用多线程的理由之一是和进程相比,它是一种非常节省的多任务操作方式。我们知道,在Linu*系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种昂贵的多任务工作方式。而运行于一个进

3、程中的多个线程,它们彼此之间使用一样的地址空间,共享大局部数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进展数据的传递只能通过通信的方式进展,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些

4、问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以防止这种为难的情况。2) 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU

5、上。3) 改善程序构造。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行局部,这样的程序会利于理解和修改。下面我们先来尝试编写一个简单的多线程程序。2. 简单的多线程编程Linu*系统下的多线程遵循POSI*线程接口,称为pthread。编写Linu*下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。顺便说一下,Linu*下pthread的实现是通过系统调用clone()来实现的。clone()是Linu*所特有的系统调用,它的使用方式类似fork,关于clone()的详细情况,有兴趣的读者可以去查看有关文档说明。下面我们展示一个最

6、简单的多线程程序e*ample1.c。 /* e*ample.c*/*include <stdio.h>*include <stdlib.h>*include <pthread.h>void thread(void)int i;for(i=0;i<3;i+)printf(This is a pthread.n); int main(void)pthread_t id;int i,ret;ret=pthread_create(&id,NULL,(void *) thread,NULL);if(ret!=0)printf (Create pthre

7、ad error!n);e*it (1);for(i=0;i<3;i+)printf(This is the main process.n);pthread_join(id,NULL);return (0); 我们编译此程序:gcc e*ample1.c -lpthread -o e*ample1运行e*ample1,我们得到如下结果:This is the main process.This is a pthread.This is the main process.This is the main process.This is a pthread.This is a pthread

8、.再次运行,我们可能得到如下结果:This is a pthread.This is the main process.This is a pthread.This is the main process.This is a pthread.This is the main process.前后两次结果不一样,这是两个线程争夺CPU资源的结果。上面的例如中,我们使用到了两个函数,pthread_create和pthread_join,并声明了一个pthread_t型的变量。pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedef unsi

9、gned long int pthread_t;它是一个线程的标识符。函数pthread_create用来创立一个线程,它的原型为:e*tern int pthread_create _P (pthread_t *_thread, _const pthread_attr_t *_attr,void *(*_start_routine) (void *), void *_arg);第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空

10、指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创立线程成功时,函数返回0,假设不为0则说明创立线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创立新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创立线程成功后,新创立的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。函数pthread_join用来等待一个线程的完毕。函数原型为:e*tern int pthread_join _P (pthread_t _th, void *_thread_return);第一个参数为被等待的线程标识符,第二个参数

11、为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程完毕为止,当函数返回时,被等待线程的资源被收回。一个线程的完毕有两种途径,一种是象我们上面的例子一样,函数完毕了,调用它的线程也就完毕了;另一种方式是通过函数pthread_e*it来实现。它的函数原型为:e*tern void pthread_e*it _P (void *_retval) _attribute_ (_noreturn_);唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thre

12、ad_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_e*it。下面,我们来了解线程的一些常用属性以及如何设置这些属性。3. 修改线程的属性在上一节的例子里,我们用pthread_create函数创立了一个线程,在这个线程中,我们使用了默认参数,即将该函数的第二个参数设为NULL。确实,对大多数程序来说,使用默认属性就够了,但我们还是有必要来了解一下线

13、程的有关属性。属性构造为pthread_attr_t,它同样在头文件/usr/include/pthread.h中定义,喜欢追根问底的人可以自己去查看。属性值不能直接设置,须使用相关函数进展操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。属性对象主要包括是否绑定、是否别离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非别离、缺省1M的堆栈、与父进程同样级别的优先级。关于线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process)。轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的

14、分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即*个线程固定的绑在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反响之类的要求。设置线程绑定状态的函数为pthread_attr_setscope,它有两个参数,第一个是指向属性构造的指针,第二个是绑定类型,它有两个取值:PTHREAD_SC

15、OPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)。下面的代码即创立了一个绑定的线程。*include <pthread.h>pthread_attr_t attr;pthread_t tid; /*初始化属性值,均设为默认值*/pthread_attr_init(&attr);pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_create(&tid, &attr, (void *) my_function, NULL); 线程的别离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,即为非别离状态,这种情况下,原有的线程等待创立的线程完毕。只有当pthread_join()函数返回时,创立的线程才算终止,才能释放自己占用的系统资源。而别离线程不是这样子的,它没有被其他的线程所等待,自

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号