说明
windows线程同步的方法主要有
互斥对象Mutex、
事件对象Event、
临界区CriticalSection、
信号量Semaphore。
下面将依次说明。
1 互斥对象
互斥对象是内核对象,包含一个使用数量,一个线程ID(标识当前拥有该对象的线程ID),一个计数器(当拥有该对象的线程多次请求该对象时也可以再次获得该对象,同时计数器增加次数,在释放该对象的时候也要释放相应次数)。
一个原则:谁拥有谁释放。
NOTE:当拥有该对象的线程退出时并且没有释放该对象,那么不管该线程请求了几次互斥对象,操作系统都会收回,并将计数器清零。
互斥量可以保证某一时刻只能有一个线程访问受保护的资源(代码段或变量等)。
①创建互斥对象
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性,可为NULL 默认安全属性
BOOL bInitOwner, //初始创建后,创建该互斥对象的线程是否拥有该对象
LPCTSTR lpName //对象名字,可为NULL,当要限制在内存中只有一个该对象的实例时要命名,根据该函数返回值判断是否已经存在。
);
eg.
HANDLE hMutex = CreateMutex(NULL, TRUE, "test"); //默认安全属性,初始创建该对象的线程拥有该对象,命名为test
if(hMutex) //如果创建了对象
{
if( ERROR_ALREADY_EXITS == GetLastError() ) //名为test的对象已经存在内存中
{
MessageBox("已经存在该对象的实例");
return;
}
//codes
}
//codes
②等待对象
DWORD WaitForSingleObject(
HANDLE hHandle, //等待的对象句柄
DWORD dwMilliseconds //等待时间,单位ms,如果为INFINITE则为无限期等待
);
返回值:
WAIT_ABANDONED:拥有互斥对象的线程结束前没有释放mutex,根据需要决定是否要继续执行
WAIT_OBJECT_0:在等待时间内等到该对象
WAIT_TIMEOUT:等待超时,根据需要决定是否要继续执行
eg.
WaitForSingleObject(hMutex, INFINITE); //无限期等待该对象
③释放对象
BOOL ReleaseMutex(
HANDLE hMutex
);
释放hMutex对象
eg.
ReleaseMutex(hMutex);
2 实例
My73MutexDlg.h 类声明中/
private:
static HANDLE m_hMutex;
public:
static UINT MyThread1(LPVOID lpParam);
static UINT MyThread2(LPVOID lpParam);
My73MutexDlg.cpp 类定义中///
HANDLE CMy73MutexDlg::m_hMutex = INVALID_HANDLE_VALUE;
//对话框初始化
BOOL OnInitDialog()
{
//codes
m_hMutex = CreateMutex(NULL, TRUE, "test"); //主线程有信号
if (m_hMutex)
{
if (ERROR_ALREADY_EXISTS == GetLastError())
{
MessageBox("只能打开一个实例");
return FALSE;
}
}
CWinThread* pThread1 = AfxBeginThread(MyThread1, (LPVOID)&m_ctrlEdit1);
CWinThread* PThread2 = AfxBeginThread(MyThread2, (LPVOID)&m_ctrlEdit2);
//主线程再次请求该互斥对象,仍然可以获得该互斥对象,对象内计数器加1
WaitForSingleObject(m_hMutex, INFINITE);
ReleaseMutex(m_hMutex); //主线程释放该对象
ReleaseMutex(m_hMutex); //主线程要释放2次,使得计数器为0
//codes
return TRUE;
}
//线程函数1
UINT CMy73MutexDlg::MyThread1(LPVOID lpParam)
{
int a = 0;
CString str;
CEdit* pEdit = (CEdit*)lpParam;
while (true)
{
WaitForSingleObject(m_hMutex, INFINITE); //请求互斥对象
str.Format("%d", ++a);
pEdit->SetWindowText(str);
Sleep(2000);
ReleaseMutex(m_hMutex); //释放互斥对象
}
return 0;
}
//线程函数2
UINT CMy73MutexDlg::MyThread2(LPVOID lpParam)
{
int b = 0;
CString str;
CEdit* pEdit = (CEdit*)lpParam;
while(true)
{
if(WAIT_ABANDONED == WaitForSingleObject(m_hMutex, INFINITE)) //如果拥有互斥对象的线程退出时没有释放mutex
{
AfxMessageBox("abandoned");
//根据需要决定是不是要继续往下执行
}
str.Format("%d", ++b);
pEdit->SetWindowText(str);
Sleep(2000);
ReleaseMutex(m_hMutex);
}
return 0;
}