线程: 4种同步(浅析)
ps: 本文只为记述某在工作学习中的所得,便于以后重新学习。如有错误,欢迎指正!
同步:协同步调,按照某种顺序先后执行,防止数据混乱。
由于线程是按时间片轮循的,所以当多个线程访问同一个数据(全局)对其进行修改时,会造成数据混乱。例如,线程A和线程B都要访问数据Data时,当A先访问对其进行修改,此时A的时间片用完,到B访问Data,再次对Data进行修改。此后在由A访问Data时,此时Data的值为B所修改的值。为了避免类似问题,可以用同步处理。
四种同步:
1.互斥
某一时刻只允许一个线程能够访问共享资源。只有当该线程执行完,其他线程才能开始执行。
代码:



运行结果:

不使用互斥结果对比:

2.信号灯
指定数量的线程按时间片轮循开始执行。比方说,有100个线程,现在只允许5个可以执行。那么这100个线程抢占资源,最先获取权限的5个线程开始执行,只有当这5个线程中的某一个运行结束,才能执行其他线程。即每有一个线程获取信号,信号灯计数-1,每执行完一个线程信号灯计数+1.计数为0时,表示饱和,无法容纳更多线程。
代码:


结果:3个线程抢占2个公共资源 先抢到的2个线程并行运行 某一个退出 第三个开始执行
ps:线程运行完记得释放,否则后续线程可能获取不到信号。

3.事件
指定某一线程执行完,才能开始执行其他指定线程。比方说,线程A执行完,才能执行线程B,线程B执行完,才能执行线程C...是一个顺序的过程。
代码:


结果:

4.临界区
跟互斥类似,只有线程进入临界区,访问共享资源时,才可以被执行,其他线程要等该线程执行完,才能开始执行。
代码:



结果:

=======================================================================================================================================
总结:
互斥: 通过CreateMutex函数来创建互斥锁,ReleaseMutex函数释放。
信号灯:通过CreateSemaphore函数创建信号灯,ReleaseSemaphore函数释放
事件: 通过CreateEvent函数创建事件,SetEvent或者PulSeEvent函数将事件设置为有信号,ResetEvent设置为无信号
互斥、信号灯、事件均通过WaitForSingleObject或WaitForMultipleObjects函数等待信号量响应
临界区:对象为结构体CRITICAL_SECTION,通过InitializeCriticalSection函数对该结构体对象进行初始化,EnterCriticalSection函数进入临界区,LeaveCriticalSection函数离开临界区。当不在需要该临界区时使用DeleteCriticalSection函数将其删除,释放系统资源(本文未处理)。
ps:互斥、信号灯、事件都是内核对象,可以跨进程使用,而临界区不是内核对象,只能在当前进程中使用。互斥与临界区两者作用基本上完全一样,在当前进程中使用时,临界区的效率明显高于互斥。一般来讲,跨进程使用互斥,不需要跨进程使用临界区。

浙公网安备 33010602011771号