1.线程(进程)同步的主要任务 windows
答:在引入多线程后,因为线程执行的异步性,会给系统形成混乱,特别是在急用临界资源时,如多个线程急用同一台打印机,会使打印结果交织在一块儿,难于区分。当多个线程急用共享变量,表格,链表时,可能会致使数据处理出错,所以线程同步的主要任务是使并发执行的各线程之间可以有效的共享资源和相互合做,从而使程序的执行具备可再现性。 多线程
2.线程(进程)之间的制约关系? 并发
当线程并发执行时,因为资源共享和线程协做,使用线程之间会存在如下两种制约关系。 异步
(1)间接相互制约。一个系统中的多个线程必然要共享某种系统资源,如共享CPU,共享I/O设备,所谓间接相互制约即源于这种资源共享,打印机就是最好的例子,线程A在使用打印机时,其它线程都要等待。 函数
(2)直接相互制约。这种制约主要是由于线程之间的合做,若有线程A将计算结果提供给线程B做进一步处理,那么线程B在线程A将数据送达以前都将处于阻塞状态。 spa
间接相互制约能够称为互斥,直接相互制约能够称为同步,对于互斥能够这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操做完毕,要么线程B等待线程操做完毕,这其实就是线程的同步了。所以同步包括互斥,互斥实际上是一种特殊的同步。 .net
3.临界资源和临界区 线程
在一段时间内只容许一个线程访问的资源就称为临界资源或独占资源,计算机中大多数物理设备,进程中的共享变量等待都是临界资源,它们要求被互斥的访问。每一个进程中访问临界资源的代码称为临界区 对象
看完概念性知识,下面用几个表格来帮助你们更好的记忆和运用多线程同步互斥的四个实现方法——关键段、事件、互斥量、信号量。 blog
关键段CS与互斥量Mutex
|
建立或初始化 |
销毁 |
进入互斥区域 |
离开互斥区域 |
关键段CS |
Initialize- CriticalSection |
Delete- CriticalSection |
Enter- CriticalSection |
Leave- CriticalSection |
互斥量Mutex |
CreateMutex |
CloseHandle |
等待系列函数如WaitForSingleObject |
ReleaseMutex |
关键段与互斥量都有“线程全部权”概念,能够将“线程全部权”理解成旅馆的房卡,在旅馆前台登记名字拥有房卡后是能够屡次进出房间的,其它人则没法进入直到你交出房卡。每一个线程必须先经过EnterCriticalSection或WaitForSingleObject来尝试得到“线程全部权”才能调用LeaveCriticalSection或ReleaseMutex。不然会调用失败,这就至关于伪造房卡去办理退房手续——因为登记本上没有你的名字因此会被拒绝。
互斥量能很好的处理“遗弃”状况,所以在多进程之间能够放心的使用。
关键段因为不能跨进程使用,因此关键段不须要处理“遗弃”问题。
事件,互斥量,信号量都是内核对象,能够跨进程使用。
事件Event
|
建立 |
销毁 |
使事件触发 |
使事件未触发 |
事件Event |
CreateEvent |
CloseHandle |
SetEvent |
ResetEvent |
注意事件的手动置位和自动置位要分清楚,不要混淆了。
信号量Semaphore
|
建立 |
销毁 |
递减计数 |
递增计数 |
信号量 Semaphore |
Create- Semaphore |
CloseHandle |
等待系列函数如WaitForSingleObject |
Release- Semaphore |
信号量在计数大于0时表示触发状态,调用WaitForSingleObject不会阻塞,等于0表示未触发状态,调用WaitForSingleObject会阻塞直到有其它线程递增了计数。
注意:互斥量,事件,信号量都是内核对象,能够跨进程使用(经过OpenMutex,OpenEvent,OpenSemaphore)。不过为何只有互斥量能解决“遗弃”状况了,请看《秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题》。