Linux多线程环境

上传人:c****d 文档编号:243009584 上传时间:2024-09-13 格式:PPT 页数:39 大小:143.50KB
返回 下载 相关 举报
Linux多线程环境_第1页
第1页 / 共39页
Linux多线程环境_第2页
第2页 / 共39页
Linux多线程环境_第3页
第3页 / 共39页
点击查看更多>>
资源描述
,*,Linux多线程环境,1,1 基本概念,引入线程原因:,在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持SMP以及减小(进程/线程)上下文切换开销。,1,原理,引入效果:,进程承担资源的分配。线程承担具体处理机的调度和信息处理,有效发挥处理机的功能,提高了并行性,程序响应快。,进程中的多个线程共享同一数据空间(用户地址空间和其他进程资源),通讯快,简单,减少了上下文切换开销, 。,改变程序设计结构,线程的概念:线程是进程内部相对独立的并具有可调度特性的执行单元。,2,1 基本概念,2,包含线程的进程结构,单线程进程结构:,PCB+用户地址空间栈段,多线程进程结构:,PCB+用户地址空间各个线程结构信息(TCB线程栈段),3,1 基本概念,3线程模型,针对线程的两大意义,分别开发出了核心级线程和用户级线程两种线程模型,分类的标准主要是线程的调度者在核内还是在核外。前者更利于并发使用多处理器的资源,而后者则更多考虑的是上下文切换开销。在目前的商用系统中,通常都将两者结合起来使用,既提供核心线程以满足smp系统的需要,也支持用线程库的方式在用户态实现另一套线程机制,此时一个核心线程同时成为多个用户态线程的调度者。,4,1 基本概念,(a) 核心级线程(KLT),线程的调度和管理等由操作系统的程序完成。系统的核心程序给应用程序提供一个可访问核心级线程的应用程序接口。即系统调用或应用程序API。系统核心来管理线程的调度与上下文切换。,特点:,1.核心程序可以把同一进程中的不同线程调度到多个处理机上运行。即支持多处理器并行处理机制。,2.当进程中的一个线程被阻塞时,进程中的另一个线程可以被调度。,3.内核程序本身也可用多线程方式编写,所以核心程序可设计成可重入的并发程序结构。,4.同一进程中的线程进行切换时需要进入到核心模式下完成。缺点。,5,1 基本概念,(b) 用户级线程(ULT),系统中线程的产生与维护完全由用户级程序实现。内核只负责以进程为单位的系统资源和处理器调度和管理。应用程序通常是建立在一个“线程控制库”基础上的多线程程序。,特点:,1.线程切换时无需改变进程的运行模式,减少了进程在核心态和用户态之间转换时的资源消耗。,2.线程的调度管理程序是用户级程序,所以线程的调度算法可以比较灵活。,3.用户级线程管理模式的系统程序移植性比较好 .,6,1 基本概念,(c) 轻量级进程,一个轻量级进程(LWP)是一个内核支持的用户线程。每个进程有一个或多个轻量级进程,每一个LWP都由一个单独的内核线程来支持,并可以将一个或多个用户级线程映射到一个核心级线程上。在一个多处理器系统中,每个LWP能被分配到不同的处理机上运行,实现并行。由于I/O等待或资源阻塞只是单个LWP而不是整个进程,在单处理器环境中优势很明显。,缺点:,由于大部分LWP的操作,如创建、释放和同步等需要系统调用。系统调用相对来说是开销很大的操作。,每个LWP需要花费相当多的内核资源,因此,一个系统不能支持大量的LWP。,7,2 多线程程序设计规则,Linux系统提供多线程机制,为用户的程序设计提供了更好的并行基础。但是多线程程序设计不同于单线程程序设计,有一些新的设计方法和规则应该引起注意。,1 多线程程序结构的改变,多线程编程可以使程序在运行中减少对系统资源的使用频率,可利用远程系统调用建立线程,并将程序的运行分布在多个处理器上完成。在编程时,应考虑以线程为核心完成程序的分布式处理,尽量使程序的设计结构简单化和独立化。,程序设计是基于线程控制库和远程系统调用包完成的。一般设计过程为:在某个主机中创建一个进程,然后让这个进程创建一系列的线程,每个线程可以完成一个远程的系统调用,而这些远程的系统调用可以去调用另一台工作站上的过程。,8,2 多线程程序设计规则,POSIX,标准:,该标准以,libpthread,线程库方式提供给用户使用。移植性好。,Solaris,多线程标准:,包含的是一套,sun,的线程接口库,libpthread,。,2,多线程标准库,9,2 多线程程序设计规则,(a),全局变量的使用规则,在单线程中,全局变量使用很常见,但在多线程中,应考虑多个线程访问同一个全局变量的数据一致性的问题。,3,多线程编程规则,extren int errno,if(write()=-1),printf(“%d”,errnno);,线程局部变量,10,2多线程程序设计规则,(b),程序代码安全性问题,应注意加入的代码是否安全。不能在一个多线程程序中随便加入非多线程语句。应使用多线程函数完成各项操作工作。,11,2 多线程程序设计规则,(c),线程间的同步和互斥,统一互斥锁法:,线程运行时为了避免对共享资源的交替使用,可以使用一个互斥锁法进行管理。类似进程管理中的互斥机制。,可重入解决方法 :,使用模块化和数据封装的设计方法,将多线程中的函数制作成“可重入式函数“。可重入函数是指某一函数同时被多个线程调用时,其执行结果仍然是正确的。即在该函数的执行中已充分考虑了多线程的隔离与同步的问题。在编写可重入函数时,其关键技术是进行代码锁定和数据锁定。,12,2 多线程程序设计规则,(1)代码锁定,使函数的整个运行过程在某个锁的保护状态下进行。,(2)数据锁定,可使用细粒度锁定 、粗粒度锁定策略来保证多线程在进行数据访问过程中数据的一致性 。,13,3 多线程程序设计基础,1 . 创建线程,#include ,int pthread_create(,pthread_t *tid,pthread_attr *attr,void (*,start_routine,)(void*),void* arg );,参数tid 用于返回新创建线程的线程号;,attr 是线程属性;,start_routine 是线程函数指针,线程从这个函数开始独立地运行;arg 是传递给线程函数的参数。,14,例:创建两个线程,一个打印Hello,另一个打印World。,#include ,Main(),pthread_t thread1,thread2;,char *msg1=“Hello”;,char *msg2=“World”;,pthread_creat(&thread1,NULL,(void)*&print_message,(void *)msg1);,pthread_creat(&thread2,NULL,(void)*&print_message,(void *)msg2);,exit(0);,Void print_message(void *ptr),char *msg;,msg=(char *)ptr;,printf(“%s”,msg);,15,例:创建两个线程,一个打印Hello,另一个打印World。,虽然这个程序简单,但是有两个明显的缺陷:,(1)因为线程是同步执行的,所以无法保证第一线程先打印,而第二个线程后打印,所以输出结果可能是“Hello world”,也可能是 “world Hello”。,(2)如果再两个线程打印之前,主程序执行到exit,那么讲没有打印结果输出。因为再主程序执行exit后,所有的线程都要终止执行。另外,如果再创建的线程中执行了exit的话,同样也将终止进程中的所有线程。,16,例:创建两个线程,一个打印Hello,另一个打印World。,为了在线程执行之后主进程才退出,我们要让主进程睡眠一会(sleep),为了让第一个线程先执行print函数,我们让主进程创建第二个线程之前再睡一会,这样修改后的程序如下:,Main(),pthread_t thread1,thread2;,char *msg1=“Hello”;,char *msg2=“World”;,pthread_creat(,sleep(10); /打算让第一个线程执行10s后再创建第二个线程,pthread_creat(,sleep(10); /打算让主线程等待10s后再退出,exit(0);,Void print_message(void *ptr), char *msg;,msg=(char *)ptr;,printf(“%s”,msg);,pthread_exit(0);,17,例:创建两个线程,一个打印Hello,另一个打印World。,上面的程序同样不能输出我们预期的结果。我们来看看上面的这两个程序的情况。在这两个程序中,实际上有三个线程,一个是主进程,另外两个是打印线程。在这三个线程中,共同的资源是 stdout,这个资源要由两个打印线程竞争。另外,这两个打印线程必须在主进程调用exit之前完成打印工作。,在上面的程序中,我们调用了sleep,实际上,当再主进程中调用sleep时,整个进程包括它的线程都挂起了。所以虽然我们使用了sleep,但是与没有使用sleep的第一程序的效果是一样的,只是程序的执行时间更长一些罢了。,18,3 多线程程序设计基础,修改线程的属性在上一节的例子里,我们用pthread_create函数创建了一个线程,在这个线程中,我们使用了默认参数,即将该函数的第二个参数设为NULL。的确,对大多数程序来说,使用默认属性就够了,但我们还是有必要来了解一下线程的有关属性。 初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。关于,线程的绑定,,牵涉到另外一个概念:轻进程(LWP:Light WeightProcess)。轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的绑在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。,19,3 多线程程序设计基础,1 . 创建线程,创建默认的属性,#include ,pthread_attr_init(pthread_attr_t * attr),用指定的属创建线程,pthread_attr_t attr;,pthread_attr_init( ,pthread_create(,20,3 多线程程序设计基础,1 . 创建线程,线程的属性,定义在结构,pthread_attr_t,中,线程是否绑定,int pthread_attr_setscope( pthread_attr_t * attr, int mode);,mode = PTHREAD_SCOPE_SYSTEM ( 绑定的 ),mode = PTHREAD_SCOPE_PROCESS ( 非绑定的 ),pthread_attr_t attr;,pthread_t tid;,pthread_attr_init (,pthread_attr_setscope (,pthread_create (,21,3 多线程程序设计基础,1 . 创建线程,线程的属性,定义在结构,pthread_attr_t,中,线程是否分离,pthread_attr_setdetachstate(pthread_attr_t *attr, int mode);,mode = PTHREAD_CREATE_DETACHED(分离线程),mode = PTHREAD _CREATE_JOINABLE(非分离线程)。,22,3 多线程程序设计基础,1 . 创建线程,线程的属性,定义在结构,pthread_attr_t,中,线程的优先级别,线程的堆栈设置,23,3 多线程程序设计基础,1 . 创建线程 简单例程:在主线程中创建一个辅线程,由辅线程完成数据库查询等后台工作,主线程在完成其他任务后,在指定点和辅线程进行同步,#include ,typedef struct phonebook_ ,char name64;,char phone64;,phonebook;,void findphone(void * arg),phonebook *p = (phonebook*)arg; /参数类型转换,/ 中间处理过程,Search(p-name, p-phone);,pthread_exit(0);,24,3 多线程程序设计基础,void main(),phonebook pb;,pthread_t tid = 0;,int status;,strcpy(pb.name,”lisi”);,pthread_create(,/ 建立新线程,并将要查的信息结构传递给线程,. . . . . . . .,pthread_join( tid, ,/ 等待线程ID为tid的线程返回,printf(“Thread has found the phone:%s”, pb.phone);,25,3 多线程程序设计基础,2 . 对线程的常用操作,#include ,int pthread_detach( pthread_t tid);,分离一个线程,#include ,void main(),pthread_t tid;,pthread_create( ,pthread_detach( tid );,. . . . .,return;,26,3 多线程程序设计基础,2 . 对线程的常用操作,#include ,int pthread_join( pthread_t tid, void* status);,等待一个线程,#include ,void main(), pthread_t tid1, tid2;,pthread_create( ,pthread_create( ,. . . . .,pthread_join( tid1, ,pthread_join( tid2, NULL );,return;,Pthread_join()暂停调用它的进程/线程的执行,直到由参数th指定的线程终止行为为止,这个线程的终止可以是调用 pthread_exit()来完成的,或者是取消了线程的执行。,27,下面的程序用来说明线程的创建和等待线程终止。,#include ,Void *process(void *arg),int i;,fprint(stderr,”stating process %sn”,(char *)arg);,for(i=0;i10000;i+),write(1,(char*)arg,1);,return NULL;,28,下面的程序用来说明线程的创建和等待线程终止。,Int main(),int retcode;,pthread_t th_a, th_b;,void *retval;,retcode=pthread_creat(,if(retcode!=0) /创建线程错误,fprintf(stderr,”create a failed %dn”,retcode);,retcode=pthread_creat(,if(retcode!=0) /创建线程错误,fprintf(stderr,”create b failed %dn”,retcode);,retcode=pthread_join(th_a, /等待线程a终止,if(retcode!=0),fprintf(stderr,”join a failed %dn”,retcode);,retcode=pthread_join(th_b, /等待线程a终止,if(retcode!=0),fprintf(stderr,”join b failed %dn”,retcode);,return 0;,29,3 多线程程序设计基础,2 . 对线程的常用操作,#include ,int pthread_exit( void* status );,线程的终止,#include ,pthread_t pthread_self();,获取线程ID,30,3 多线程程序设计基础,3 . 线程中使用的数据,int pthread_key_create(,pthread_key_t *key,void( * destructor )(void *),);,int pthread_key_delete( pthread_key_t key );,int pthread_setspecific( pthread_key_t key,void *v);,int pthread_getspecific( pthread_key_t key,void *v);,函数pthread_key_creat()创建一个对进程中的所有线程都可见的关键字。这个关键字可以通过函数pthread_setspecific()和pthread_getspecific()来设置和读取,31,3 多线程程序设计基础,3 . 线程中使用的数据 示例,void thread_routine( void * p),/线程入口函数,char buff1024;,/该内存区域设定为线程数据区域,pthread_key_create(56789, NULL );,/,创建一个线程数据键,pthread_setspecific( 56789, buff );,/指定线程数据区域,strcpy(buff,” write data to thread data zone!”);,. . . . . . . .,function1();,/线程内部调用函数,. . . . . . .,function2();,/线程内部调用函数,. . . . . . .,printf(“the data is %s”, buff );,pthread_key_delete( 56789 );,/删除线程数据键,. . . . .,pthread_exit(0);,32,3 多线程程序设计基础,void function1,char *p = null;,pthread_getspecific( 56789, ,/通过数据键获取线程数据内存指针,printf(“the data in thread data zone:%s”, p);,strcat(p, “data from function1”);,void function2,char *q = null;,pthread_getspecific( 56789, ,/通过数据键获取线程数据内存指针,printf(“the data in thread data zone:%s”, q);,strcat(q, “data from function2”);,33,3 多线程程序设计基础,4 . 线程中使用互斥锁,int pthread_mutex_init (,pthread_mutex_t *mutex,pthread_mutexattr_t *mutex_attr,);,int pthread_mutex_destroy ( pthread_mutex_t * mutex),int pthread_mutex_lock ( pthread_mutex_t * mutex);,int pthread_mutex_unlock(pthread_mutex_t * mutex) ;,34,3 多线程程序设计基础,4 . 线程中使用互斥锁 示例,include ,void reader_function ( void *p);,void writer_function ( void *p);,char* buffer;,int buffer_has_item=0;,pthread_mutex_t mutex,;,/定义互斥量,struct timespec delay;,void main ( void ),pthread_t reader;,delay.tv_sec = 2; delay.tv_nec = 0;,/设置延迟时间,pthread_mutex_init (,/初始化互斥量,pthread_create(&reader, NULL,reader_function, NULL);,writer_function( NULL );,/用读者函数作为线程入口,在主线程中执行写者,辅线程中执行读者,. . .,35,3 多线程程序设计基础,void writer_function (void *p),while(1) ,pthread_mutex_lock (,/ 锁定互斥锁,if (buffer_has_item=0),buffer=make_new_item( );,buffer_has_item=1;,pthread_mutex_unlock(,/ 解开互斥锁,pthread_delay_np(,void reader_function(void *p),while(1),pthread_mutex_lock(,/ 锁定互斥锁,if( buffer_has_item=1) ,consume_item(buffer);,buffer_has_item=0;,pthread_mutex_unlock(,/ 解开互斥锁,pthread_delay_np(,36,3 多线程程序设计基础,5 . 线程综合示例:使用多线程的方式进行多个文件备份。,#define MAX 50,int main(int argc, char *argv),pthread_t tidMAX;,int , i ;,int fdMAX2;,char 256;,= argc 1;,for (int i = 0; i ; i+ ),sprintf(,”%s.bak”,argvi+1);,fdi0 = open(argvi+1,O_RDONLY);,fdi1 = open();,37,3 多线程程序设计基础,for ( i = 0; i ; i+ ),pthread_create( &tidi, null,backup_file, (void*)fdi );,for ( i = 0; i 0 ) ,len = len + i;,write( backupfile, buf, i);,close( srcfile ); close( backupfile);,printf(“ Thread%d backup %d bytesn”, tid, len);,pthread_exit(0);,39,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!