Mutex 和 CS都有“线程所有权”的概念,由于Mutex是内核对象,因此可以处理不同进程中的多线程互斥问题,但是由于是内核,所以速度相比于CS会慢一些,CS相比于Mutex虽然快,但只能处理同一个进程间的多线程互斥。
下面将展示一段代码,启动50个线程,并分别打印线程的编号和一个全局的变量
using namespace std;
int gNum;
unsigned int __stdcall ThreadWrite(void *p);
CriSection cs;
int main()
{
const int iCount = 50;
HANDLE handle[iCount];
gNum = 0;
// 创建50个线程,每个线程中都会打印i
for(int i = 0;i<iCount;i++)
{
handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadWrite, &i, 0, NULL);
}
WaitForMultipleObjects(iCount, handle, TRUE, INFINITE);
return 1;
}
unsigned int __stdcall ThreadWrite(void *p)
{
int i = *(int*)p;
Sleep(50);
gNum++;
cout<<"线程编号:"<<i<<" 全局变量:"<<gNum<<endl;
return 0;
}
运行结果看上去很混乱,因为,多个线程之间没有任何的互斥,大家都去对gNum执行加1操作,稍有技术功底的人都知道,为何不互斥就会导致这个问题出现,这里就不再赘述,我们可以用Mutex和CS来解决这个问题,在实际应用中,为了使用方便,还会对他们进行封装
#include<windows.h>
class BaseLock
{
private:
bool bLock;
public:
virtual ~BaseLock(){};
// 必须实现,且不能在函数内改变成员变量
virtual void Lock()const = 0;
virtual void UnLock()const = 0;
};
class Mutex:public BaseLock
{
private:
HANDLE m_mutex;
public:
Mutex();
~Mutex();
void Lock()const;
void UnLock()const;
};
class CriSection:public BaseLock
{
private:
CRITICAL_SECTION m_critclSection;
public:
CriSection();
~CriSection();
void Lock()const;
void UnLock()const;
};
class Lock
{
private:
// 此处只能使用引用
const BaseLock& m_Lock;
public:
Lock(const BaseLock& lock);
~Lock();
};
#include"Lock.h"
Mutex /
Mutex::Mutex()
{
m_mutex = CreateMutex(NULL,FALSE,NULL);
}
Mutex::~Mutex()
{
CloseHandle(m_mutex);
}
void Mutex::Lock()const
{
DWORD d = WaitForSingleObject(m_mutex,INFINITE);
}
void Mutex::UnLock()const
{
ReleaseMutex(m_mutex);
}
/// CriSection //
CriSection::CriSection()
{
InitializeCriticalSection(&m_critclSection);
}
CriSection::~CriSection()
{
DeleteCriticalSection(&m_critclSection);
}
void CriSection::Lock()const
{
EnterCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
}
void CriSection::UnLock()const
{
LeaveCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
}
/ Lock ///
Lock::Lock(const BaseLock& lock):m_Lock(lock)
{
m_Lock.Lock();
}
Lock::~Lock()
{
m_Lock.UnLock();
}
这样封装后,使用起来会非常方便
#include <process.h>
#include <iostream>
#include <vector>
#include"Lock.h"
#include"WinTree.h"
#include"A.h"
using namespace std;
int gNum;
unsigned int __stdcall ThreadWrite(void *p);
CriSection cs;
int main()
{
const int iCount = 50;
HANDLE handle[iCount];
gNum = 0;
// 创建50个线程,每个线程中都会打印i
for(int i = 0;i<iCount;i++)
{
handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadWrite, &i, 0, NULL);
}
WaitForMultipleObjects(iCount, handle, TRUE, INFINITE);
return 1;
}
unsigned int __stdcall ThreadWrite(void *p)
{
Lock lock(cs);
int i = *(int*)p;
Sleep(50);
gNum++;
cout<<"线程编号:"<<i<<" 全局变量:"<<gNum<<endl;
return 0;
}
在进行互斥时,只需调用Lock lock(cs);即可,不用关系退出和释放问题,因为对象析构的时候会进行这一步操作