进程、线程同步互斥学习 —— 信号量
来源:互联网 发布:mac可以远程控制吗 编辑:程序博客网 时间:2024/06/14 01:33
关于信号量,先看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
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 10CSemaphores 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时未进行互斥操作,所以测试结果可能会出现以下结果:
- 进程、线程同步互斥学习 —— 信号量
- 进程、线程同步互斥学习 —— 临界区
- 进程、线程同步互斥学习 —— 互斥器
- 进程、线程同步互斥学习 —— 事件
- 线程同步与互斥——信号量
- 进程间通信学习总结2---信号量互斥同步
- 线程同步(信号量,互斥,条件变量)
- linux 线程互斥同步By信号量
- 信号量------线程的同步与互斥
- 进程-线程-同步-互斥
- Linux系统编程——进程同步与互斥:POSIX有名信号量
- Linux系统编程——进程同步与互斥:System V 信号量
- Linux系统编程——进程同步与互斥:POSIX有名信号量
- Linux系统编程——进程同步与互斥:System V 信号量
- 线程互斥与同步(part3)—解决线程同步的”扛把子“:单身狗-信号量( Semaphore)
- Linux系统编程——线程同步与互斥:POSIX无名信号量
- Linux入门:线程同步与互斥(三)——信号量
- Linux系统编程——线程同步与互斥:POSIX无名信号量
- Cisco 中line密码的几点理解
- Execution failed for task ': :dexDebug'
- LeetCode Search for a Range
- android ant 多渠道打包
- 【Extjs】上传文件
- 进程、线程同步互斥学习 —— 信号量
- require.js的用法
- 计算机视觉(ComputerVision, CV)相关领域的网站链接
- Visual Studio查找高亮效果设置
- 《Linux内核设计与实现》读书笔记(十二)- 内存管理
- #笔记#圣思园 JavaWeb 第7讲——Servlet
- iOS面试题总结与感想
- could not initialize proxy - no Session
- 南京肇事宝马司机妻子:愿给每家补偿5万元