第四章:同步控制

1.理解同步与异步的概念

2.Critical Sections:

(1)critical sections:是指“用来处理一份被共享之资源”的程序代码。如内存、数据结构、文件等。

(2)critical section并不是核心对象,存在于进程的内存中。

(3)VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);初始化CRITICAL_SECTION类型变量。

(4)VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);清除CRITICAL_SECTION类型变量。

(5)VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);线程进入,锁定lpCriticalSection。

(6)VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);线程离开,解除锁定。

(7)一旦线程进入一个 critical section,它就能够一再地重复进入该 critical section。唯一的警告就是,每一个“进入”操作都必须有一个对应的“离开”操作。

(8)不要长时间锁住一份资源:千万不要在一个 criticalsection 之中调用 Sleep() 或任何 Wait...() API 函数。

(9)避免Danling Critical Sections:Windows NT 和 Windows 95 在管理dangling critical sections 时有极大的不同。在 Windows NT 之中,如果一个线程进入某个 critical section 而在未离开的情况下就结束,该 critical section 会被永远锁住。然而在 Windows 95 中,如果发生同样的事情,其他等着要进入该 critical section 的线程,将获准进入。这基本上是一个严重的问题,因为你竟然可以在你的程序处于不稳定状态时进入该 critical section。

3.死锁

(1)任何时候当一段代码需要两个(或更多)资源时,都有潜在性的死锁阴影。

(2)强制将资源锁定,使它们成为“all-or-nothing”,可以阻止死锁的发生。

(3)哲学家进餐问题:WaitForMutipleObjects,只能用于核心对象,引出了Mutex。

4.互斥器(Mutexes)

(1)锁住Mutex比critical section 慢,因为要切换到OS核心态。

(2)Mutexes 可跨进程使用,Critical section 只能在同一个进程中使用。

(3)等待一个 mutex 时,可以指定“结束等待”的时间长度。但对于critical section 则不行。

(4)mutex、critical section相关函数比较:

InitializeCriticalSection() CreateMutex()
OpenMutex()
EnterCriticalSection() WaitForSingleObject()
WaitForMultipleObjects()
MsgWaitForMultipleObjects()
LeaveCriticalSection() ReleaseMutex()
DeleteCriticalSection() CloseHandle()

(5)创建mutex时指定名称,使其能跨进程使用。mutex名称是全局性的。

(6)HANDLE CreateMutex(

LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性,NULL表示使用默认的属性
BOOL bInitialOwner, //TRUE表示调用这个函数的线程拥有该mutex
LPCTSTR lpName //mutex名称,不能包含\
);

(7)“mutex 激发状态”:当没任何线程拥有该 mutex 而且有一个线程正以 Wait...() 等待该 mutex,该mutex 就会短暂地出现激发状态,使 Wait...() 得以返回。

(8)Bool ReleaseMutex(Handle hMutex) 释放mutex

(9)Mutex 的拥有权并非属那个产生它的线程,而是那个最后对此 mutex 进行 Wait...() 操作并且尚未进行 ReleaseMutex() 操作的线程。

(10)处理被舍弃的互斥器:如果线程拥有一个 mutex 而在结束前没有调用 ReleaseMutex(),mutex 不会被摧毁。取而代之的是,该 mutex会被视为“未被拥有”以及“未被激发”,而下一个等待中的线程会被以WAIT_ABANDONED_0 通知。如果其他线程正以 WaitForMultipleObjects() 等待此 mutex,该函数也会返回,传回值介于 WAIT_ABANDONED_0 和 (WAIT_ABANDONED_0_n +1)之间,其中的 n 是指handle 数组的元素个数。线程可以根据这个值了解到究竟哪一个 mutex 被放弃了。至于WaitForSingleObject() , 则只是传回WAIT_ABANDONED_0。

(11)CreateMutex() 的第二个参数 bInitialOwner,允许你指定现行线程(current thread)是否立刻拥有即将产生出来的mutex。乍见之下这个参数或许只是提供一种方便性,但事实上它阻止了一种 race condition 的发生,如果没有bInitialOwner,你就必须写下这样的代码:

HANDLE hMutex = CreateMutex(NULL, FALSE, "Sample Name");
int result = WaitForSingleObject(hMutex, INFINITE);

但是这样的安排可能会产生 race condition。

(12)一个线程拥有了某个mutex,后面的wait…()不会被阻塞。

5.信号量

(1)HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES lpAttributes, //安全属性,默认NULL
LONG lInitialCount, //semaphore的初值,必须大于或等于0,小于等于IMaximumCount
LONG lMaximumCount, //semaphore最大值,同一时间能够锁住semaphore之线程的最大数。
LPCTSTR lpName //semaphore的名称,NULL表示没有名字
);

(2)Semaphore没有拥有权的概念,一个线程可以反复调用 Wait...() 函数以产生新的锁定。

这和 mutex绝不相同:拥有 mutex 的线程不论再调用多少次 Wait...() 函数,也不会被阻塞住。

(3)BOOL ReleaseSemaphore(

HANDLE hSemaphore, //semaphore的handle
LONG lReleaseCount, //semaphore现值的增额,不可以是负值或0
LPLONG lpPreviousCount //借此传回semaphore原来的现值
);

注意:lpPreviousCount 所传回来的是一个瞬间值。你不可以把lReleaseCount 加上 *lpPreviousCount,就当作是 semaphore 的现值,因为其他线程可能已经改变了 semaphore 的值。

(4)设定semaphore初值的意义与CreateMutex() 的 bInitialOwner 参数的存在理由是一样的

6.事件

(1)Event的唯一目的就是成为激发或未激发状态,这两种状态全由程序控制。

(2)HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性,NULL默认
BOOL bManualReset,//FALSE表示event在变成激发状态之后,自动重置为非激发状态,TRUE表示需要调用ResetEvent才能重置
BOOL bInitialState,//TRUE表示一开始处于激发状态,FALSE处于非激发状态
LPCTSTR lpName //event名称
);

(3)三个操作函数:

SetEvent:把event对象设为激发状态

ResetEvent:把event对象设为非激发状态

PulseEvent:对应Manual Reset Event:把event设为激发状态,唤醒所有等待线程,然后event恢复为非激发状态。

对应Auto Reset Event:把event设为激发状态,唤醒一个等待线程,然后event恢复为非激发状态

(4)如果你面对一个 AutoReset event 对象调用 SetEvent() 或 PulseEvent(),而彼时并没有任何线程正在等待。这种情况下这个 event 会被遗失.

7.Interlocked Variables

(1) InterlockedIncrement,加1后与0比较,对应于 AddRef()操作

(2) InterlockedDecrement,减1后与0比较,对应于Release()操作

(3) InterlockedExchange设定一个新值,传回旧值,多线程安全。

优质内容筛选与推荐>>
1、tkinter--Text(3)
2、hibernate5.2.6新特性
3、.htaccess文件使用手册
4、大数据平台架构技术选型与场景运用
5、C++之const


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号