进程、线程同步互斥学习 —— 临界区
2015-06-18 18:52
441 查看
关于临界区,MSDN是这样介绍的:
Critical Section Objects
A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Event, mutex,
and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster,more efficient mechanism for mutual-exclusion synchronization
(a processor-specific test and set instruction). Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. Unlike a mutex object, there is no way
to tell whether a critical section has been abandoned.
临界区是保证某个时刻只有一个线程访问数据的最简单,高效的方法,临界区只能被一个进程拥有。
初始化
The process is responsible for allocating the memory used by a critical section. Typically, this is done by simply declaring a variable of typeCRITICAL_SECTION. Before the threads of the process can use it, initialize
the critical section by using theInitializeCriticalSection orInitializeCriticalSectionAndSpinCount function.
第一个参数都为一个指向要初始化的CS的指针,dwSpinCount是旋转数。
关于SpinCount(旋转数):
On multiprocessor systems, if the critical section is unavailable, the calling thread spindwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section
becomes free during the spin operation, the calling thread avoids the wait operation.
Spinning means that when a thread tries to acquire a critical section that is locked, the thread enters a loop, checks to see if the lock is released, and if the lock is not released, the thread goes to sleep. On single-processor
systems, the spin count is ignored and the critical section spin count is set to 0 (zero). On multiprocessor systems, if the critical section is unavailable, the calling thread spinsdwSpinCount times before performing a wait operation on a semaphore
that is associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.
即:当线程试图进入另一线程的临界区时,线程不会立即进入等待,而是进行dwSpinCount次尝试进入临界区失败后,才进入等待状态。使用SpinCount次数循环判断临界区是否可以进入,减少了上下文切换(context switch)所消耗的CPU时间,增加了SpinCount的循环开销。
进入临界区
A thread uses the
EnterCriticalSection orTryEnterCriticalSection function to request ownership of a critical section. It uses theLeaveCriticalSection
function to release ownership of a critical section. If the critical section object is currently owned by another thread,EnterCriticalSection waits indefinitely for ownership. In contrast, when a mutex object is used for mutual exclusion,
the wait functions accept a specified time-out interval. TheTryEnterCriticalSection function attempts to enter a critical section without blocking the calling thread.
When a thread owns a critical section, it can make additional calls toEnterCriticalSection orTryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself
while waiting for a critical section that it already owns.
The difference is that TryEnterCriticalSection returns immediately, regardless of whether it obtained ownership of the critical section, whileEnterCriticalSection blocks until the thread
can take ownership of the critical section.
即:TryEnterCriticalSection以非阻塞尝试进入临界区,EnterCriticalSection相反。
退出临界区
When it has finished executing the protected code, the thread uses the LeaveCriticalSection function
to relinquish ownership, enabling another thread to become the owner and gain access to the protected resource. The thread must call LeaveCriticalSection once for each
time that it entered the critical section.
注:If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread usingEnterCriticalSection towait
indefinitely.
删除临界区
Deleting a critical section object releases all system resources used by the object.
After a critical section object has been deleted, do not reference the object in any function that operates on critical sections (such asEnterCriticalSection,TryEnterCriticalSection,
andLeaveCriticalSection) other thanInitializeCriticalSection andInitializeCriticalSectionAndSpinCount. If you attempt
to do so, memory corruption and other unexpected errors can occur.
If a critical section is deleted while it is still owned, the state of the threads waiting for ownership of the deleted critical section is undefined.
实例:
Lock.h
测试结果:
Critical Section Objects
A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Event, mutex,
and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster,more efficient mechanism for mutual-exclusion synchronization
(a processor-specific test and set instruction). Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. Unlike a mutex object, there is no way
to tell whether a critical section has been abandoned.
临界区是保证某个时刻只有一个线程访问数据的最简单,高效的方法,临界区只能被一个进程拥有。
初始化
The process is responsible for allocating the memory used by a critical section. Typically, this is done by simply declaring a variable of typeCRITICAL_SECTION. Before the threads of the process can use it, initialize
the critical section by using theInitializeCriticalSection orInitializeCriticalSectionAndSpinCount function.
void WINAPI InitializeCriticalSection( __out LPCRITICAL_SECTION lpCriticalSection ); BOOL WINAPI InitializeCriticalSectionAndSpinCount( __inout LPCRITICAL_SECTION lpCriticalSection, __in DWORD dwSpinCount );即:初始化CRITICAL_SECTION的function,InitializeCriticalSection和InitializeCriticalSectionAndSpinCount
第一个参数都为一个指向要初始化的CS的指针,dwSpinCount是旋转数。
关于SpinCount(旋转数):
On multiprocessor systems, if the critical section is unavailable, the calling thread spindwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section
becomes free during the spin operation, the calling thread avoids the wait operation.
Spinning means that when a thread tries to acquire a critical section that is locked, the thread enters a loop, checks to see if the lock is released, and if the lock is not released, the thread goes to sleep. On single-processor
systems, the spin count is ignored and the critical section spin count is set to 0 (zero). On multiprocessor systems, if the critical section is unavailable, the calling thread spinsdwSpinCount times before performing a wait operation on a semaphore
that is associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.
即:当线程试图进入另一线程的临界区时,线程不会立即进入等待,而是进行dwSpinCount次尝试进入临界区失败后,才进入等待状态。使用SpinCount次数循环判断临界区是否可以进入,减少了上下文切换(context switch)所消耗的CPU时间,增加了SpinCount的循环开销。
进入临界区
A thread uses the
EnterCriticalSection orTryEnterCriticalSection function to request ownership of a critical section. It uses theLeaveCriticalSection
function to release ownership of a critical section. If the critical section object is currently owned by another thread,EnterCriticalSection waits indefinitely for ownership. In contrast, when a mutex object is used for mutual exclusion,
the wait functions accept a specified time-out interval. TheTryEnterCriticalSection function attempts to enter a critical section without blocking the calling thread.
When a thread owns a critical section, it can make additional calls toEnterCriticalSection orTryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself
while waiting for a critical section that it already owns.
void WINAPI EnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); BOOL WINAPI TryEnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection );EnterCriticalSection与TryEnterCriticalSection区别:
The difference is that TryEnterCriticalSection returns immediately, regardless of whether it obtained ownership of the critical section, whileEnterCriticalSection blocks until the thread
can take ownership of the critical section.
即:TryEnterCriticalSection以非阻塞尝试进入临界区,EnterCriticalSection相反。
退出临界区
When it has finished executing the protected code, the thread uses the LeaveCriticalSection function
to relinquish ownership, enabling another thread to become the owner and gain access to the protected resource. The thread must call LeaveCriticalSection once for each
time that it entered the critical section.
void WINAPI LeaveCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection );当需要保护的代码结束后,离开临界区。
注:If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread usingEnterCriticalSection towait
indefinitely.
删除临界区
Deleting a critical section object releases all system resources used by the object.
After a critical section object has been deleted, do not reference the object in any function that operates on critical sections (such asEnterCriticalSection,TryEnterCriticalSection,
andLeaveCriticalSection) other thanInitializeCriticalSection andInitializeCriticalSectionAndSpinCount. If you attempt
to do so, memory corruption and other unexpected errors can occur.
If a critical section is deleted while it is still owned, the state of the threads waiting for ownership of the deleted critical section is undefined.
void WINAPI DeleteCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection );
实例:
Lock.h
#pragma once #include <windows.h> //接口 class ILock { public: virtual void lock() = 0; virtual void unlock() = 0; }; //临界区封装 class CriticalSection : public ILock { public: CriticalSection(DWORD dwSpinCount = 0); ~CriticalSection(); DWORD setCSspincount(DWORD dwSpinCount = 0); virtual void lock(); virtual void unlock(); private: CRITICAL_SECTION m_cs; }; //锁 class CLock { public: CLock(ILock&); ~CLock(); private: ILock& m_lock; };Lock.cpp
#include "stdafx.h" #include "Lock.h" CriticalSection::CriticalSection(DWORD dwSpinCount /* = 0 */) { if (dwSpinCount > 0) { ::InitializeCriticalSectionAndSpinCount(&m_cs, dwSpinCount); } else { ::InitializeCriticalSection(&m_cs); } } CriticalSection::~CriticalSection() { ::DeleteCriticalSection(&m_cs); } void CriticalSection::lock() { ::EnterCriticalSection(&m_cs); } void CriticalSection::unlock() { ::LeaveCriticalSection(&m_cs); } DWORD CriticalSection::setCSspincount(DWORD dwSpinCount /* = 0 */) { return ::SetCriticalSectionSpinCount(&m_cs, dwSpinCount); } CLock::CLock(ILock& locker) : m_lock(locker) { m_lock.lock(); } CLock::~CLock() { m_lock.unlock(); }test.cpp
#include "stdafx.h" #include <iostream> #include <process.h> #include "Lock.h" #define THREADCOUNT 10 CriticalSection g_eatCs; int nFood = 0; unsigned int WINAPI EatThread(void *pParam) { int i = (int)pParam; int nHasEaten = 0; while (true) { Sleep(100); //局部对象 CLock lock(g_eatCs); if (nFood > 0) { std::cout << "消费者" << i << "进行消费,已经吃掉("<< ++nHasEaten <<"),当前剩余食物" << --nFood << std::endl; } else { break; } } return 0; } unsigned int WINAPI ProductThread(void *pParam) { int i = 0; while (i < 50) { std::cout << "生产者进行生产,当前剩余食物" << ++nFood << std::endl; i++; } a4aa return 0; } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hProductThread; HANDLE hEatThread[THREADCOUNT]; hProductThread = (HANDLE)_beginthreadex(NULL, 0, &ProductThread,(void *)0, 0, 0); // WaitForSingleObject(hProductThread, INFINITE); for (int i = 0; i < THREADCOUNT; i++) { hEatThread[i] = (HANDLE)_beginthreadex(NULL, 0, &EatThread, (void *)i, 0, 0); } WaitForMultipleObjects(THREADCOUNT, hEatThread, TRUE, INFINITE); ::CloseHandle(hProductThread); for (int i = 0; i < THREADCOUNT; i++) { ::CloseHandle(hEatThread[i]); } system("pause"); return 0; }
测试结果:
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++中拷贝构造函数的应用详解
- C++中引用(&)的用法与应用实例分析
- C++使用CriticalSection实现线程同步实例
- C++智能指针实例详解
- 解析C++ 浮点数的格式化输出