第4章程序、进程和线程_第1页
第4章程序、进程和线程_第2页
第4章程序、进程和线程_第3页
第4章程序、进程和线程_第4页
第4章程序、进程和线程_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章程序、进程和线程,进程的概念是操作系统最重要的核心概念之一,对进程的不同实现方式造成了目前操作系统的一种分类方法,例如DOS系统为单进程的操作系统。在本章中将介绍Linux中的进程的概念和相关的操作函数,并对线程的程序设计方法进行了比较多的介绍。进程、线程和程序的概念和它们之间的区别。进程的产生方式,fork、system、exec等。详细介绍了Linux进程间的通信和同步方式,包括管道pipe,命名管道fifo,信号量sem,共享缓冲区shm,消息队列msg,以及信号signal。对其原理和编程函数进行了详细的讲解,并举了丰富的代码例子。对Linux下的线程编程方式进行了比较详细的介绍,并介绍了互斥、条件变量、线程信号等的编程实现方法。,4.1程序、进程和线程的概念,在计算机上运行的程序是一组指令及指令参数的组合,指令按照既定的逻辑控制计算机运行。进程则是运行着的程序,是操作系统执行的基本单位。线程则是为了节省资源而可以在同一个进程中共享资源的一个执行单位。,4.1.1程序和进程的差别,进程概念和程序概念最大的不同之处在于:进程是动态的,而程序是静态的。进程有一定的生命期,而程序是指令的集合,本身无“运动”的含义。没有建立进程的程序不能作为1个独立单位得到操作系统的认可。一个进程只能对应一个程序,一个程序可以对应多个进程。进程和程序的关系就像戏剧和剧本之间的关系。,4.1.2Linux环境下的进程,Linux的进程操作方式主要有产生进程、终止进程,并且进程之间存在数据和控制的交互,即进程间通信和同步。1进程的产生过程2进程的终止方式3进程之间的通信4进程之间的同步,4.1.3进程和线程,线程和进程是另一对有意义的概念,主要区别和联系如下:进程是操作系统进行资源分配的基本单位,进程拥有完整的虚拟空间。进行系统资源分配的时候,除了CPU资源之外,不会给线程分配独立的资源,线程所需要的资源需要共享。线程是进程的一部分,如果没有进行显示的线程分配,可以认为进程是单线程的;如果进程中建立了线程,则可以认为系统是多现成的。多线程和多进程是两种不同的概念,虽然二者都是并行完成功能。但是,多个线程之间像内存、变量等资源在多个线程之间可以通过简单的办法共享,多进程则不同,进程间的共享方式有限。,4.2进程产生的方式,进程是计算机中运行的基本单位,要产生一个进程,有多种产生方式,例如使用fork()函数、system()函数、exec()函数等,这些函数的不同在于其运行环境的构造之间存在差别,其本质都是对程序运行的各种条件进行设置,在系统之间建立一个可以运行的程序。,4.2.1进程号,每个进程在初始化的时候,系统都分配了一个id号,用于标识此进程。在Linux中进程号是唯一的,系统可以用这个值来表示一个进程,描述进程的id号通常叫做PID,即进程id(processid)。PID的变量类型为pid_t。1函数getpid()介绍2函数getpid()的例子,4.2.2进程复制fork(),产生进程的方式比较多,fork()是其中的一种方式。fork()函数以父进程为蓝本复制一个进程,其id号和父进程id号不同。在Linux环境下,fork()是以写复制实现的,只有内存等与父进程不同,其他与父进程共享,只有在父进程或者子进程进行了修改后,才重新生成一份。1函数fork()介绍2函数fork()的例子,4.2.3system()方式,system()函数调用shell的外部命令在当前进程中开始另一个进程。1函数system()介绍2函数system()的例子,4.2.4进程执行exec()函数系列,在使用fork()函数和system()函数的时候,系统中都会建立一个新的进程,执行调用者的操作,而原来的进程还会存在,直到用户显示的退出;而exec()族的函数与之前的fork()和system()函数不同,exec()族函数会用新进程代替原有的进程,系统会从新的进程运行,新的进程的PID值会与原来进程的PID值相同。1函数exec()介绍2函数ececve()的例子,4.2.5所有用户态进程的产生进程init,在Linux系统中,所有的进程都是有父子或者堂兄关系的,没有哪个进程与其他进程完全独立。除了初始进程init,系统中每个进程都有一个父进程,新的进程不是被全新的创建,新的进程通常是从一个原有的进程进行复制或者克隆的。Linux操作系统下的每一个进程都有一个父进程或者兄弟进程,并且有自己的子进程。,4.3进程间通讯和同步,在Linux下的多个进程间的通信机制叫做IPC,它是多个进程之间进行相互沟通的一种方法。在Linux下有多种进程间通信的方法:半双工管道、FIFO(命名管道)、消息队列、信号量、共享内存等。使用这些通信机制可以为Linux下的网络服务器开发提供灵活而又坚固的框架。,4.3.1半双工管道,管道是一种把两个进程之间的标准输入和标准输出连接起来的机制。管道是一种历史悠久的进程间通信的办法,自从UNIX操作系统诞生,管道就存在了。1基本概念2函数pipe()介绍3函数pipe()的例子4管道阻塞和管道操作的原子性5管道操作原子性的代码6管道原子性的例子运行结果,4.3.2命名管道,命名管道的工作方式与普通的管道非常相似,但也有一些明显的区别。在文件系统中命名管道是以设备特殊文件的形式存在的。不同的进程可以通过命名管道共享数据。1创建FIFO2FIFO操作,4.3.3消息队列,消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容。消息顺序地发送到消息队列中,并以几种不同的方式从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识。内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相对独立的。每个消息队列中的消息,又构成一个独立的链表1消息缓冲区结构2结构msgid_ds3结构ipc_perm4内核中的消息队列关系5键值构建函数ftok()5获得消息函数msgget()6发送消息函数msgsnd()7接收消息函数msgrcv():8消息控制函数msgctl(),4.3.3消息队列,4.3.4消息队列的一个例子,本例在建立建立消息队列后,打印其属性,并在每次发送和接收后均查看其属性,最后对消息队列进行了修改。1显示消息属性的函数msg_show_attr()2主函数main(),4.3.5信号量,信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常常被用作一个锁机制,在某个进程正在对特定资源进行操作时,信号量可以防止另一个进程去访问它。生产者和消费者的模型是信号量的典型使用。本小节中介绍了信号量的概念和常用的函数,并对信号量进行包装形成了一整套用户可以理解的信号量函数。1信号量数据结构2新建信号量函数semget()3信号量操作函数semo()4控制信号量参数semctl()5一个信号量操作的例子,4.3.6共享内存,共享内存是多个进程之间共享内存区域的一种进程间通信方式,它是在多个进程之间进行对内存段进行映射的方式实现内存共享的。这是IPC最快捷的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式的方式则是需要将数据通过中间机制进行转换;与此相反,共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅是地址不同而已,因此不需要进行复制,可以直接使用硕慰占洹1创建共享内存函数shmget()2获得共享内存地址函数shmat()3删除共享内存函数shmdt()4共享内存控制shmctl()5一个共享内存的例子,4.3.7信号,信号(signal)机制是UNIX系统中最为古老的进程之间的通信机制。它用于在一个或多个进程之间传递异步信号。信号可以由各种异步事件产生,例如键盘中断等。Shell也可以使用信号将作业控制命令传递给它的子进程。Linux系统中定义了一系列的信号,这些信号可以由内核产生,也可以由系统中的其他进程产生,只要这些进程有足够的权限。1信号截取函数signal()2向进程发送信号函数kill()和raise(),4.4Linux下的线程,线程的概念早在60年代就被提出,但是在操作系统中真正使用多线程实在80年代的中期,在使用线程方面,Solaris是其中的先驱。在传统的UNIX系统中,线程的概念也被使用,但是一个线程对应着一个进程,因此多线程编程了多进程,线程的真正有点没有得到发挥。现在,多线程的技术在操作系统中已经得到普及、被很多操作系统所采用,其中包括Windows操作系统和Linux系统。与传统的进程相比较,用线程来实现相同的同能有如下的优点:系统资源消耗低速度快线程间的数据共享比进程间容易得多,4.4.1多线程编程实例,Linux系统下的多线程遵循POSIX标准,叫做pthread,读者可以使用“manpthread”在Linux系统下查看系统对线程的解释。编写Linux下的线程需要包含头文件pthread.h,在生成可执行文件的时候需要链接库libpthread.a或者libpthread.so。,4.4.2Linux下线程创建函数pthread_create(),在4.4.1小节的例子中,用到了两个线程相关的函数pthread_create()和pthread_join()。函数pthread_create()用于创建一个线程,函数pthread_join()等待一个线程的退出。在函数pthread_create()函数调用时,传入的参数有线程属性、线程函数、线程函数变量,用于生成一个某种特性的线程,线程中执行线程函束。创建线程使用函数pthread_create(),它的原型为:intpthread_create(pthread_t*thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg);,4.4.3线程的结束函数pthread_join()和pthread_exit(),函数pthread_join()用来等待一个线程运行结束。这个函数是阻塞函数,一直到被等待的线程结束为止,函数才返回并且收回被等待线程的资源。函数原型为:externintpthread_join_P(pthread_t_th,void*_thread_return);,4.4.4线程的属性,在上例中,用pthread_create()函数创建线程时,使用了默认参数,即将该函数的第二个参数设为NULL。通常来说,建立一个线程的时候,使用默认属性就够了,但是很多时候需要调整线程的属性,特别是线程的优先级。1线程的属性结构2线程的优先级3线程的绑定状态4线程的分离状态,4.4.5线程间的互斥,互斥锁是用来保护一段临界区的,它可以保证某时间段内只有一个线程在执行一段代码或者访问某个资源。下面一段代码是一个生产者/消费者的实例程序程序,生产者生产数据,消费者消耗数据,它们共用一个变量,每次只有一个线程访问此公共变量:1线程互斥的函数介绍2线程互斥函数的例子,4.4.6线程中使用信号量,信号量的主要函数有信号量初始化函数sem_init()、信号量的销毁函数sem_destroy()、信号量的增加函数sem_post()、信号量的减少函数sem_wait()等。还有一个函数sem_trywait(),它的含义与互斥的函数pthread_mutex_trylock()是一致的,先对资源是否可用进行判断。函数的原型在头文件semaphore.h中定义。1线程信号量初始化函数sem_init()2线程信号量增加函数sem_post()3线程信号量等待函数sem_wait()4线程信号量销毁函数sem_destroy()5线程信号量的例子,4.5小结,本章介绍了Linux环境下进程和线程的概念和编程方法。进程、线程和程序概念的异同主要集中于进程和程序之间的动态和静态、进

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论