3、信号量
信号量,相当于一个计数器,用于限制可使用资源线程的数目。信号量允许多个线程在同一时刻访问共享资源,但是需要限制通一时刻访问此资源的最大线程数目。
CSemaphore类构造函数
CSemaphore(
LONG lInitialCount = 1,
LONG lMaxCount = 1,
LPCTSTR pstrName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes = NULL
);
参数说明:
lInitialCount:信号量对象的初始计数值,即可访问线程数目的初始值,取值范围 0≤lInitialCount≤lMaxCount
lMaxCount:信号量对象的计数最大值,即同一时刻可访问资源的最大线程数目
pstrName:信号量的名字
lpsaAttributes :信号量的安全属性
用法:
CSemaphore*m_pSemaphore;声明一个信号量对象
m_pSemaphore= new CSemaphore(2,3);新建一个信号量对象
WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE);等待信号量,如果为最大值,则一直等待
ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL);信号量减少1
示例:
#include "threadTest.h"
#include <afxmt.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
using namespace std;
CSemaphore* m_pSemaphore;
CCriticalSection cs;
DWORD WINAPI myFunProc1(LPVOID lpParaneter);
DWORD WINAPI myFunProc2(LPVOID lpParaneter);
DWORD WINAPI myFunProc3(LPVOID lpParaneter);
DWORD WINAPI myFunProc4(LPVOID lpParaneter);
int total = 100;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("错误: MFC 初始化失败\n"));
nRetCode = 1;
}
else
{
m_pSemaphore = new CSemaphore(2,3);
HANDLE thread[4];
thread[0] = CreateThread(NULL,0,myFunProc1,NULL,0,NULL); thread[1] = CreateThread(NULL,0,myFunProc2,NULL,0,NULL); thread[2] = CreateThread(NULL,0,myFunProc3,NULL,0,NULL); thread[3] = CreateThread(NULL,0,myFunProc4,NULL,0,NULL); WaitForMultipleObjects(4,thread,TRUE,INFINITE);
for (int i = 0;i<4;i++)
{
CloseHandle(thread[i]);
}
return 0;
}
}
else
{
_tprintf(_T("错䨪误¨®: GetModuleHandle 失º¡ì败㨹\n"));
nRetCode = 1;
}
return nRetCode;
}
DWORD WINAPI myFunProc1(LPVOID lpParaneter)
{
while (total)
{
//等待信号量,如果为最大数目,则一直等待
WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE);
cs.Lock();
cout<<"线程1访问共享资源"<<endl;
cs.Unlock();
Sleep(200);
//信号量计数减少1
ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL);
}
return 0;
}
DWORD WINAPI myFunProc2(LPVOID lpParaneter)
{
while (total)
{
//等待信号量,如果为最大数目,则一直等待
WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE);
cs.Lock();
cout<<"线程2访问共享资源"<<endl;
cs.Unlock();
Sleep(200);
//信号量计数减少1
ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL);
}
return 0;
}
DWORD WINAPI myFunProc3(LPVOID lpParaneter)
{
while (total)
{
//等待信号量,如果为最大数目,则一直等待
WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE);
cs.Lock();
cout<<"线程3访问共享资源"<<endl;
cs.Unlock();
Sleep(200);
//信号量计数减少1
ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL);
}
return 0;
}
DWORD WINAPI myFunProc4(LPVOID lpParaneter)
{
while (total)
{
//等待信号量,如果为最大数目,则一直等待
WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE);
cs.Lock();
cout<<"线程4访问共享资源"<<endl;
cs.Unlock();
Sleep(200);
//信号量计数减少1
ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL);
}
return 0;
}
4、互斥量(Mutex)
互斥量对象与临界区对象很相似,互斥对象和临界区都可以用于各个线程间。当然使用临界区会更节省系统资源,而且更有效率。但是互斥对象可以再进程间是用,而临界区对象只能在同一进程的各个线程之间是用。
CMutex定义:
CMutex(
BOOL bInitiallyOwn = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL
);
参数说明:
bInitiallyOwn:指定如果创建CMutex对象,是否最初获得资源控制
lpszName:互斥量名字ID
lpsaAttribute:通常设为NULL
使用方法:
CMutex m_Mutex(FALSE, “MutexName”);创建互斥对象
m_Mutex.Lock();加锁
m_Mutex.UnLock();解锁
示例:
#include "threadTest.h"
#include <afxmt.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApptheApp;
using namespace std;
char szMutexText[] = "Mutex_1";
CMutexm_Mutex(FALSE, szMutexText);
CEventm_Event(FALSE, FALSE);
DWORDWINAPI myFunProc1(LPVOID lpParaneter);
inttotal = 100;
int_tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode= 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule!= NULL)
{
if(!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("错误:MFC 初始化失败\n"));
nRetCode = 1;
}
else
{
cout << "程序进入MAIN函数" << endl;
m_Mutex.Lock();
cout << "程序进入互斥量" << endl;
m_Event.ResetEvent();
HANDLE hThread = CreateThread(NULL,0, myFunProc1, NULL, 0, NULL);
WaitForSingleObject(m_Event.m_hObject,INFINITE);
m_Mutex.Unlock();
return0;
}
}
else
{
_tprintf(_T("错误:GetModuleHandle 失败\n"));
nRetCode = 1;
}
returnnRetCode;
}
DWORDWINAPI myFunProc1(LPVOID lpParaneter)
{
Sleep(5000);
m_Event.SetEvent();
return 0UL;
}
编译本程序可生成threadTest.exe文件,运行两个此可执行文件,可看到先开启的进程会打印出两行文字“程序进入MAIN函数”和“程序进入互斥量”,第二个只打出一行“程序进入MAIN函数”,等待5秒后第二个进程才打印出“程序进入互斥量”。这说明互斥对象可以在进程间使用。