线程同步:信号量Semaphore的使用

时间:2021-04-08 15:14:23

<1>WIN32中信号量使用

1、win32中创建信号量对象CreateSemaphore()

 1) win32中头文件

#include <windows.h>

2)函数原型

HANDLE CreateSemaphore(

    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD

    LONG lInitialCount, // initial count

    LONG lMaximumCount, // maximum count

    LPCTSTR lpName// object name

);

 

3)参数说明

 

 

lpemaphoreAttributes

该参数定义了信号量的安全特性,设为NULL表示采用不允许继承的默认安全性。

 

lInitialCount

设置信号量的初始计数。可设置零到lMaximumCount之间的一个值

lMaximumCount

设置信号量的最大计数

 

 

lpName

指定信号量对象的名称。用NULL可创建一个未命名的信号量对象。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。这个名字可能不与一个现有的互斥体、事件、可等待计时器或文件映射的名称相符

4)返回值

如执行成功,返回信号量对象的句柄;零表示出错。

倘若同名的一个信号量已经存在,那么GetLastError会返回ERROR_ALREADY_EXISTS

5)说明

当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发。

在对信号量调用等待函数(WaitForMultipleObjects)时,等待函数会检查信号量的当前资源计数,如果大于0(即信号量处于触发状态),1后返回让调用线程继续执行。一个线程可以多次调用等待函数来减小信号量。

6)信号量的销毁

由于信号量是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。

 

2、win32中递增信号量的当前资源计数ReleaseSemaphore ()

1) win32中头文件

#include <windows.h>

2)函数原型

BOOL ReleaseSemaphore

(

  HANDLE hSemaphore,

  LONG lReleaseCount,  

  LPLONG lpPreviousCount 

);

3)参数说明

 

hSemaphore

信号量的句柄。

lReleaseCount

表示增加个数,必须大于0且不超过最大资源数量。

lpPreviousCount

可以用来传出先前的资源计数,设为NULL表示不需要传出。

4)返回值

如果成功返回TRUE。

如果失败返回FALSE,可以调用GetLastError函数得到详细出错信息。(如果当前信号量数量加上这个值会导致信号量的当前值大于信号量创建时指定的最大值,那么这个信号量的当前值不变,同时这个函数返回FALSE)

5)WIN32示例

// ThreadTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <process.h>
#include <windows.h>
#include <iostream>
using namespace std;
class myHandle
{
public:
HANDLE semaphoreHandle[3];
HANDLE threadHandle[10];
}myHandl;
unsigned int _stdcall FunA(void *)
{
/*static int j=0;
cout<<"第"<<j++<<"次"<<endl;*/
cout<<"A";
ReleaseSemaphore(myHandl.semaphoreHandle [1],1,NULL);//递增信号量B的资源数
return 0;
}
unsigned int _stdcall FunB(void*)
{
cout<<"B";
ReleaseSemaphore(myHandl.semaphoreHandle [2],1,NULL);//递增信号量C的资源数
return 0;
}
unsigned int _stdcall FunC(void*)
{

cout<<"C"/*<<endl*/;
ReleaseSemaphore(myHandl.semaphoreHandle [0],1,NULL);//递增信号量A的资源数
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
myHandl.semaphoreHandle[0]=CreateSemaphore(NULL,1,1,NULL);
myHandl.semaphoreHandle[1]=CreateSemaphore(NULL,0,1,NULL);
myHandl.semaphoreHandle[2]=CreateSemaphore(NULL,0,1,NULL);
int i=0;
while(i<10)
{
/*Sleep(10);
cout<<"第"<<i<<"次"<<endl;*/
WaitForSingleObject(myHandl.semaphoreHandle [0],INFINITE);
myHandl.threadHandle[i]=(HANDLE)_beginthreadex(NULL,0,FunA,&i,0,NULL);
WaitForSingleObject(myHandl.semaphoreHandle [1],INFINITE);
myHandl.threadHandle [i]=(HANDLE)_beginthreadex(NULL,0,FunB,&i,0,NULL);
WaitForSingleObject(myHandl.semaphoreHandle [2],INFINITE);
myHandl.threadHandle [i]=(HANDLE)_beginthreadex(NULL,0,FunC,&i,0,NULL);
++i;
}
DWORD index=WaitForMultipleObjects(10,myHandl.threadHandle ,true,INFINITE);
for(int j=0;j<3;j++)
CloseHandle(myHandl.semaphoreHandle [j]);
for(int k=0;k<10;k++)
CloseHandle(myHandl.threadHandle [k]);

return 0;
}

<2>MFC中信号量类CSemaphore使用

(1)MFC中头文件

"afxmt.h"

(2)创建信号量对象

①类的构造函数原型

CSemaphore

(

LONG lInitialCount=1,

LONG lMaxCount=1,

LPCTSTR pstrName=NULL,

LPSECURITY_ATTRIBUTES  lpsaAttributes=NULL

);

参数说明与CreateSemaphore相同,只是注意参数顺序不同。

②对象创建

CSemaphore mySema(1,1);

③对象句柄的获取

mySema.m_hObject


 (3)递增信号量的当前资源计数  ReleaseSemaphore

  与WIN32的完全相同

  (4)使用示例

创建对话框.cpp中添加代码

#include "afxmt.h"
CSemaphore mySema(1,1);
UINT myThreadFunc1(LPVOID lp)
{
WaitForSingleObject(mySema/*.m_hObject */,INFINITE);
//可以使用mySema.m_hObject来获取对象句柄,也可以直接使用对象mySema
AfxMessageBox(_T("线程1正在运行!"));
ReleaseSemaphore(mySema/*.m_hObject*/ ,1,NULL);
return 0;
}
UINT myThreadFunc2(LPVOID lp1)
{
WaitForSingleObject(mySema.m_hObject ,INFINITE);
AfxMessageBox(_T("线程2正在运行!"));
ReleaseSemaphore(mySema.m_hObject ,1,NULL);
return 0;
}


初始化类::OnInitDialog()中添加

HANDLE threadhHandle1=AfxBeginThread(myThreadFunc1,NULL);
HANDLE threadhHandle2=AfxBeginThread(myThreadFunc2,NULL,0,0,0,0);</span>