进程、线程同步互斥学习 —— 信号量
2015-06-25 17:15
387 查看
关于信号量,先看MSDN介绍:
Semaphore Objects
A semaphore object is a synchronization object that
maintains a count between zero and a specified maximum value. The count is decremented each time a thread completes a wait for the semaphore object and incremented each time a thread releases the semaphore. When the count reaches zero, no more threads
can successfully wait for the semaphore object state to become signaled.
The state of a semaphore is set to signaled when its count is greater than zero, and nonsignaled when its count is zero.The semaphore object is useful in controlling a shared resource that can support a limited number
of users. It acts as a gate that limits the number of threads sharing the resource to a specified maximum number.
For example, an application might place a limit on the number of windows that it creates. It uses a semaphore with a maximum count equal to the window limit, decrementing the count whenever a window is created and incrementing
it whenever a window is closed.
即:信号量不同于临界区,信号量可以限定一定数量线程去执行关键代码,通过P(Wait)、V(Signal)操作来实现对当前可执行关键代码线程的管理。当信号量大于0时为有信号状态,等于0为无信号状态。线程对信号量操作可以影响信号量中的计数器,通过计数器可以控制线程进入关键代码的数量。
初始化
A thread uses the
CreateSemaphore orCreateSemaphoreEx function to create a semaphore object. The creating thread specifies the initial count and the maximum value of the count for the object.
The initial count must be neither less than zero nor greater than the maximum value. The creating thread can also specify a name for the semaphore object. Threads in other processes can open a handle to an existing semaphore object by specifying its name in
a call to theOpenSemaphore function.
此处介绍CreateSemaphore和CreateSemaphoreEx
lInitialCount Long 设置信号量的初始计数。可设置零到lMaximumCount之间的一个值
lMaximumCount Long 设置信号量的最大计数。
lpName String,指定信号量对象的名称。用vbNullString可创建一个未命名的信号量对象。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。这个名字可能不与一个现有的互斥体、事件、可等待计时器或文件映射的名称相符。
dwFlags 此参数必须为0。
dwDesiredAccess 定义信号量的访问权限。
wait操作
Before a thread attempts to perform the task, it uses theWaitForSingleObject function to determine whether the semaphore's current count permits it to do so. The wait function's time-out
parameter is set to zero, so the function returns immediately if the semaphore is in the nonsignaled state.
WaitForSingleObject decrements the semaphore's count by one.
即:WaitForSingleObject等待信号量dwMilliseconds毫秒,超时或者正常返回都将让信号量的count 执行减1操作,直到信号量为0。
signal操作
The ReleaseSemaphore function increases a semaphore's count by a specified amount.
The count can never be less than zero or greater than the maximum value.
即:让信号量的count执行加1操作,但是不会高于MaximumCount.
lReleaseCount 这个信号量对象在当前基础上所要增加的值,这个值必须大于0,如果信号量加上这个值会导致信号量的当前值大于信号量创建时指定的最大值,那么这个信号量的当前值不变,同时这个函数返回FALSE;
lpPreviousCount 指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,那么这个参数可以设置为NULL;返回值:如果成功返回TRUE,如果失败返回FALSE,可以调用GetLastError函数得到详细出错信息;
测试代码:
Lock.h
Semaphore Objects
A semaphore object is a synchronization object that
maintains a count between zero and a specified maximum value. The count is decremented each time a thread completes a wait for the semaphore object and incremented each time a thread releases the semaphore. When the count reaches zero, no more threads
can successfully wait for the semaphore object state to become signaled.
The state of a semaphore is set to signaled when its count is greater than zero, and nonsignaled when its count is zero.The semaphore object is useful in controlling a shared resource that can support a limited number
of users. It acts as a gate that limits the number of threads sharing the resource to a specified maximum number.
For example, an application might place a limit on the number of windows that it creates. It uses a semaphore with a maximum count equal to the window limit, decrementing the count whenever a window is created and incrementing
it whenever a window is closed.
即:信号量不同于临界区,信号量可以限定一定数量线程去执行关键代码,通过P(Wait)、V(Signal)操作来实现对当前可执行关键代码线程的管理。当信号量大于0时为有信号状态,等于0为无信号状态。线程对信号量操作可以影响信号量中的计数器,通过计数器可以控制线程进入关键代码的数量。
初始化
A thread uses the
CreateSemaphore orCreateSemaphoreEx function to create a semaphore object. The creating thread specifies the initial count and the maximum value of the count for the object.
The initial count must be neither less than zero nor greater than the maximum value. The creating thread can also specify a name for the semaphore object. Threads in other processes can open a handle to an existing semaphore object by specifying its name in
a call to theOpenSemaphore function.
此处介绍CreateSemaphore和CreateSemaphoreEx
HANDLE WINAPI CreateSemaphore( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, __in LONG lInitialCount, __in LONG lMaximumCount, __in_opt LPCTSTR lpName ); HANDLE WINAPI CreateSemaphoreEx( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, __in LONG lInitialCount, __in LONG lMaximumCount, __in_opt LPCTSTR lpName, __reserved DWORD dwFlags, __in DWORD dwDesiredAccess );lpSemaphoreAttributes SECURITY_ATTRIBUTES 该参数定义了信号量的安全特性。
lInitialCount Long 设置信号量的初始计数。可设置零到lMaximumCount之间的一个值
lMaximumCount Long 设置信号量的最大计数。
lpName String,指定信号量对象的名称。用vbNullString可创建一个未命名的信号量对象。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。这个名字可能不与一个现有的互斥体、事件、可等待计时器或文件映射的名称相符。
dwFlags 此参数必须为0。
dwDesiredAccess 定义信号量的访问权限。
wait操作
Before a thread attempts to perform the task, it uses theWaitForSingleObject function to determine whether the semaphore's current count permits it to do so. The wait function's time-out
parameter is set to zero, so the function returns immediately if the semaphore is in the nonsignaled state.
WaitForSingleObject decrements the semaphore's count by one.
即:WaitForSingleObject等待信号量dwMilliseconds毫秒,超时或者正常返回都将让信号量的count 执行减1操作,直到信号量为0。
DWORD WINAPI WaitForSingleObject( __in HANDLE hHandle, __in DWORD dwMilliseconds );
signal操作
The ReleaseSemaphore function increases a semaphore's count by a specified amount.
The count can never be less than zero or greater than the maximum value.
即:让信号量的count执行加1操作,但是不会高于MaximumCount.
BOOL WINAPI ReleaseSemaphore( __in HANDLE hSemaphore, __in LONG lReleaseCount, __out_opt LPLONG lpPreviousCount );hSemaphore 要操作的信号量对象的句柄,这个句柄必须有SEMAPHORE_MODIFY_STATE 的权限。
lReleaseCount 这个信号量对象在当前基础上所要增加的值,这个值必须大于0,如果信号量加上这个值会导致信号量的当前值大于信号量创建时指定的最大值,那么这个信号量的当前值不变,同时这个函数返回FALSE;
lpPreviousCount 指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,那么这个参数可以设置为NULL;返回值:如果成功返回TRUE,如果失败返回FALSE,可以调用GetLastError函数得到详细出错信息;
测试代码:
Lock.h
#pragma once #include <windows.h> class ILock { public: virtual void lock() = 0; virtual void unlock() = 0; }; class CSemaphores : public ILock { public: CSemaphores(__in LONG lInitialCount,__in LONG lMaximumCount); ~CSemaphores(); virtual void lock(); virtual void unlock(); private: HANDLE m_hSemaphore; }; class CLock { public: CLock(ILock&); ~CLock(); private: ILock& m_lock; };Lock.cpp
#include "stdafx.h" #include "Lock.h" #include <assert.h> CSemaphores::CSemaphores(__in LONG lInitialCount, __in LONG lMaximumCount) { assert(lInitialCount >= 0 && lMaximumCount >= 0 && lInitialCount <= lMaximumCount); m_hSemaphore = ::CreateSemaphore(NULL, lInitialCount, lMaximumCount, NULL); //失败 assert(m_hSemaphore); } CSemaphores::~CSemaphores() { CloseHandle(m_hSemaphore); } void CSemaphores::lock() { WaitForSingleObject(m_hSemaphore, INFINITE); } void CSemaphores::unlock() { ::ReleaseSemaphore(m_hSemaphore, 1, NULL); } 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 CSemaphores g_semaphore(3,3); int nFood = 0; unsigned int WINAPI EatThread(void *pParam) { int i = (int)pParam; int nHasEaten = 0; while (true) { //局部对象 CLock lock(g_semaphore); if (nFood > 0 ) { Sleep(100); std::cout << "消费者" << i << "进行消费,已经吃掉(" << ++nHasEaten << "),当前剩余食物" << --nFood << std::endl; Sleep(1000); } else { break; } } return 0; } unsigned int WINAPI ProductThread(void *pParam) { int i = 0; while (i < 52) { std::cout << "生产者进行生产,当前剩余食物" << ++nFood << std::endl; i++; } 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; }此处测试信号量最大为3,即最多可以有三个线程同时访问,由于在三线程同时进行访问nFood时未进行互斥操作,所以测试结果可能会出现以下结果:
相关文章推荐
- 使用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++ 浮点数的格式化输出