在早期的操作系统中,各个任务的执行完全是串行的,只有在一个任务运行完成之后,另一个任务才会被执行,我们称之为单道程序
。
而现代操作系统引入了多道程序
的并发概念:
多道程序:当一个程序暂时不需要使用CPU的时候,系统会把该程序挂起或中断,此时其他程序可以使用CPU,多个任务在操作系统的控制中实现了宏观上的并发。undefined多道程序提升了计算机资源的利用率,但是也引起了多个任务对系统资源的抢夺,在开发上极为不便。
串行与并发是同一个维度的概念,区别是:
并行与并发并不是同一个维度上的概念:
并发与并行概念的区别是是否同时执行,比如吃饭时,电话来了,需要停止吃饭去接电话,接完电话继续吃饭,这是并发执行,但是吃饭时电话来了,边吃边接是并行。
进程:就是二进制可执行文件在计算机内存中的运行实例,可以简单理解为:一个.exe文件是个类,进程就是该类new出来的实例。 进程是操作系统资源分配的最小单位(如虚拟内存资源),所有代码都是在进程中执行的。
在Unix系统中,操作系统启动后将会运行进程号(PID)为1的一个进程 init 进程,该进程是所有其他进程的父进程。操作系统通过 fork() 函数能够创建多个子进程,从而能够提升计算机资源的利用率。
进程在创建后会拥有自己的独立地址空间,操作系统会提供一个数据结构PCB来描述该进程(Process Control Block,进程控制块),PCB中保存了进程的管理、控制信息等数据。
由于进程拥有互相独立的地址空间,所以进程之间无法直接通信,必须利用进程间通信(IPC,InterProcess Communication)方式来实现通信。
操作系统的内存会被划分为两大区域:
我们不难发现,库函数其实是在系统调用函数基础上再次进行了封装,方便开发者使用。当然开发者既可以使用库函数来操作文件,也可以直接使用底层的系统调用函数(但是这样需要做很多错误处理)。
程序在运行时,CPU有两种状态:
操作系统之所以要这样设计是出于内存的安全考虑,内核地址只有内核自己的函数(系统调用函数)才能使用!
线程:操作系统基于进程开启的轻量级进程,是操作系统调度执行的最小单位(即cpu分配时间轮片的对象)
一个进程内部可以创建多个线程,他们与进程一样拥有独立的PCB,但是没有独立的地址空间,即线程之间共享了地址空间。这样也让线程之间无需IPC,直接就能通信!!(因为他们在同一个地址空间内)。
虽然线程带来了通信的便利,但是如果同一空间的中多个线程同时去修改同一个数据,就会造成资源竞争问题,这是计算机编程中最复杂的问题!
进程和线程都是操作系统级别的,协程与他们并不是一个维度的概念,所以类似《现代操作系统》的书籍并未提出协程的概念。
贴士:千万不要将协程理解为轻量级线程!
协程:程序在执行时,函数内部可以中断,适当时候返回接着执行,即协程运行在用户态
协程的优势在于其轻量级、执行效率高:
线程需要上下文不停切换,而协程不会主动交出使用权,除非代码中主动要求切换,或者发生I/O,此时会切换到别的协程,这样能更好的解决并发问题。
线程同步:线程在发出某一个功能调用时,如果没有得到结果,则该调用不返回。此时其他线程不能调用该功能(因为要保证数据一致性)。
线程同步是为了避免引起数据混乱。实际上,多个控制流共同操作一个共享资源,都需要同步,比如:进程、线程、信号之间都需要同步机制,常见的线程同步技术就是互斥锁。
同步的作用是避免在并发访问共享资源时可能发生的冲突。
同步的理念:
除了使用同步方式来实现并发程序数据的交互之外,还可以使用数据传递方式(也称为通信)。
该方式可以使数据不加延迟的发送给数据接收方。即使数据接收方还没有为接收数据做好准备,也不会造成数据发送方的等待。数据会被临时存储在一个称谓通信缓存的数据结构中。通信缓存是一种特殊的数据结构,可以同时被多个程序使用,数据接收方可以在准备就绪之后按照数据存入通信缓存的顺序接收它们。
目前流行的并发理念是:异步非阻塞I/O,协程。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。