进程、线程详解

第一章 进程、线程之初级探秘


前言

进程和线程作为码农行业的入门基础知识,在我们初学阶段都会学到,在日常工作当中也会经常使用到。虽然接触的时间横跨我们整个编程生涯,不过,总会产生一种囫囵吞枣、管中窥豹的感觉。这样虽然不会影响工作进行,但是时常会让我产生困惑,我真的理解他们的含义了么,我该使用多进程还是多线程。基于想解决这种不明晰感觉的目的,打算遍查资料并结合自身经验写几章博文铭记一下。博文采用讲故事与理论结合的方式进行描述,希望更加的通俗易懂。那么故事开始…
故事情节:采用开发商扮演操作系统,施工楼号扮演进程,浇筑工、钢筋工等工人扮演线程,资源车扮演CPU寄存器。

一、进程是什么?

进程的百度解释:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

1.核心概念

一是:拥有自己的地址空间的实体。地址空间包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文件区域存储我们编写的程序代码,数据区域存储变量、堆存储动态分配的内存,栈存储局部变量及运行栈帧。这跟我们的房子很像,有卧室、客厅、厨房、厕所等区域。
二是:执行中的程序。程序本身是死的,被执行以后才是活的,才能称之为进程。进程可以占用cpu完成程序代码的执行。

2.进程特性介绍

动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
(1)多道程序设计技术:是在计算机内存中同时存放几道相互独立的程序,使它们在管理程序控制下,相互穿插运行,两个或两个以上程序在计算机系统中同处于开始到结束之间的状态, 这些程序共享计算机系统资源。与之相对应的是单道程序,即在计算机内存中只允许一个的程序运行。
并发性:任何进程都可以同其他进程一起并发执行
(1)对于一个单CPU系统来说,程序同时处于运行状态只是一种宏观上的概念,他们虽然都已经开始运行,但就微观而言,任意时刻,CPU上运行的程序只有一个。
(2)现在存在双cpu主板,可以安装两块cpu,理论上讲两块cpu可以支持两个进程同一时刻运行,但在网上没有找到相关的资料。双cpu主板高功耗和高成本,一般用于服务器端。
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
结构特征:进程由程序、数据和进程控制块三部分组成。
(1)程序段:存放程序代码。
(2)数据段:存放程序运行时使用、产生的运算数据,如全局变量、局部变量、宏定义的常量。
(3)进程控制块:是操作系统核心中一种数据结构,它存放着操作系统用于描述进程情况及控制进程运行所需的全部信息,如进程描述信息、进程控制和管理信息、资源分配清单、处理机相关信息。

3.进程切换

进程切换:就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。这里所说的从某个进程收回处理器,实质上就是把进程存放在处理器的寄存器中的中间数据找个地方存起来,从而把处理器的寄存器腾出来让其他进程使用。
进程占用处理器:实质上是把某个进程存放在私有堆栈中寄存器的数据(前一次本进程被中止时的中间数据)再恢复到处理器的寄存器中去,并把待运行进程的断点送入处理器的程序指针PC,于是待运行进程就开始被处理器运行了,也就是这个进程已经占有处理器的使用权了。
进程的上下文:在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的 切换实质上就是被中止运行进程与待运行进程上下文的切换。在进程未占用处理器时,进程 的上下文是存储在进程的私有堆栈中的。
个人理解:进程和cpu的关系就像房子和资源车之间的关系,但运行逻辑有点区别,房子接收资源车的物资,并将生产过程的垃圾交由资源车运走,这样支撑起房子的建造过程;进程将私有堆栈中的中间数据存储到cpu寄存器中,并将进程的断点送入cpu的程序指针pc,cpu知道了进程的运行起点和运行数据,就可以通过运算器等部件运行了。

4.进程如何切换

进程上下文切换由以下4个步骤组成:
(1)决定是否作上下文切换以及是否允许作上下文切换。包括对进程调度原因的检查分析,以及当前执行进程的资格和CPU执行方式的检查等。在操作系统中,上下文切换程序并不是每时每刻都在检查和分析是否可作上下文切换,它们设置有适当的时机。
(2)保存当前执行进程的上下文。这里所说的当前执行进程,实际上是指调用上下文切换程序之前的执行进程。如果上下文切换不是被那个当前执行进程所调用,且不属于该进程,则所保存的上下文应是先前执行进程的上下文,或称为“老”进程上下文。显然,上下文切换程序不能破坏“老”进程的上下文结构。
(3)选择就绪进程。使用进程调度算法,选择一处于就绪状态的进程。
(4)执行选择进程。恢复或装配所选进程的上下文,将CPU控制权交到所选进程手中。

5.进程切换注意事项

(1)保存处理器PC寄存器的值到被中止进程的私有堆栈;
(2)保存处理器PSW寄存器的值到被中止进程的私有堆栈;
(3)保存处理器SP寄存器的值到被中止进程的进程控制块;
(4)保存处理器其他寄存器的值到被中止进程的私有堆栈;
(5)自待运行进程的进程控制块取SP值并存入处理器的寄存器SP;
(6)自待运行进程的私有堆栈恢复处理器各寄存器的值;
(7)自待运行进程的私有堆栈中弹出PSW值并送入处理器的PSW;
(8)自待运行进程的私有堆栈中弹出PC值并送入处理器的PC。

6.进程同步、互斥

(1)进程异步:各自并发执行的进程由于各自是独立的,所以会以不可预知的速度先前推进,就是你不能提前预料到它们将来是怎么执行的。
(2)进程同步:它是指为了完成某个任务而建立起的两个或多个进程,这些进程在完成任务时,需要协调它们之间的执行顺序。
(3)临界资源:我们把同一时间内只允许一个人进程使用的资源叫做临界资源。例如打印机,摄像头。而对临界资源的访问,必须要互斥地访问。
(4)进程互斥:当一个进程访问临界资源时,另一个进程想访问临界资源就必须等待。等第一个进程访问完,第二个进程才能去访问。

7进程互斥原则

(1)空闲让进:临界区空闲时,可以允许一个请求访问临界区的进程立即访问临界区。
(2)忙则等待:当已经有进程进入临界区时,其他想访问临界区的进程必须等待。
(3)有限等待:对请求访问临界区的进程,应保证其能在 有限的时间内进入临界区。(保证不会饥饿)
(4)让权等待:当进程不能进入临界区时,应立即释放处理机(cpu),防止进程忙等待。

8进程通信方式

(1)管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
(2)命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(3)消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(4)共享内存SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
(5)信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(6)套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
(7)信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

二、线程是什么?

1.核心概念

一是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
二是同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。
三是同一进程中的多个线程有各自的存储环境。自己的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
四是线程运行的本质。线程运行的本质其实就是函数的执行,函数的执行总会有一个源头,这个源头就是所谓的入口函数,CPU从入口函数开始执行从而形成一个执行流,只不过我们人为的给执行流起一个名字,这个名字就叫线程。
线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

2.线程特性介绍

轻型实体:在多线程OS中,通常是在一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费最小开销的实体。线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。线程的实体包括程序、数据和TCB。线程是动态概念,它的动态特性由线程控制块TCB(Thread Control Block)描述。
独立调度和分派的基本单位。在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(在同一进程中的)。
可并发执行。在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;同样,不同进程中的线程也能并发执行,充分利用和发挥了处理机与外围设备并行工作的能力。
共享进程资源。在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。

3.线程分类

主线程:程序启动时,操作系统会创建一个进程,与此同时会立即运行一个线程,该线程通常被称为主线程。主线程的作用主要有两个,一个是产生其他子线程,另一个是最后执行各种关闭操作,例如文件的关闭。
子线程:程序中创建的其它线程。
守护线程(后台线程):守护线程是在后台为其它线程提供服务的线程,它独立于程序,不会因程序的终止而结束。当进程中只剩下守护线程时,进程直接退出。
前台线程:相对于守护线程的其它线程称为前台线程。

4.线程切换

线程上下文(thread context):是指所属线程私有的栈区、程序计数器、栈指针以及函数运行使用的寄存器等信息。
(1)栈区:函数的参数、局部变量、返回地址、寄存器初始值。
(2)程序计数器:存储cpu的运行指令。
(3)栈指针:指向函数的地址,用于函数切换。
线程间共享资源:代码区、数据区、堆区、打开文件、动态链接库
(1)代码区:我们编写的代码编译后的可执行机器指令。
(2)数据区:全局变量,静态变量。
(3)堆区:我们在C/C++中用malloc或者new出来的数据就存放在这个区域。
(4)栈区:一个线程能拿到来自另一个线程栈帧上的指针,那么该线程就可以改变另一个线程的栈区。举例:线程函数的指针传参。
(5)动态链接库:编译器在将可执行程序翻译成机器指令后,进行链接,链接完成后生成可执行程序。
(6)文件:在运行过程中打开了一些文件,那么进程地址空间中还保存有打开的文件信息,进程打开的文件也可以被所有的线程使用,这也属于线程间的共享资源。
线程的切换在进程的内部,是指令间的切换,价值在哪?例如网页浏览器的显示问题,需要从远端服务器下载数据,下载完毕后再显示文本数据,再显示图片数据,这样做有两个缺点:
(1)用户体验查,不知道网络是否掉线了,漫无目的等待的时间长。
(2)占用内存大。网络数据下载完后,全部存储到内存中,在显示的过程中,还要遍历数据类型并掉用对应显示程序显示。

5.线程通信方式

线程之间的通信方式有以下几种:
1.消息队列,是最常用的一种,也是最灵活的一种,通过自定义数据结构,可以传输复杂和简单的数据结构。
在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程默认自带消息队列和消息循环,工作线程需要手动实现消息循环),因此可以采用消息进行线程间通信sendMessage,postMessage。
定义消息#define WM_THREAD_SENDMSG=WM_USER+20;
添加消息函数声明afx_msg int OnTSendmsg();
添加消息映射ON_MESSAGE(WM_THREAD_SENDMSG,OnTSM)
添加OnTSM()的实现函数;
在线程函数中添加PostMessage消息Post函数
2.使用全局变量
进程中的线程间内存共享,这是比较常用的通信方式和交互方式。
注:定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。
3.使用事件CEvent类实现线程间通信
Event对象有两种状态:有信号和无信号,线程可以监视处于有信号状态的事件,以便在适当的时候执行对事件的操作。
1)创建一个CEvent类的对象:CEvent threadStart;它默认处在未通信状态;
2)threadStart.SetEvent();使其处于通信状态;
3)调用WaitForSingleObject()来监视CEvent对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值