
本文链接:
Mutex和Critical Section都是主要用于限制多线程(Multithread)对全局或共享的数组、对象或存储空间的访问。下面是其主要的优劣点(不同的地方用绿色表示)。
Critical Section
性能和速率
慢。
Mutex是内核对象,相关变量的执行(WaitForSingleObject,
ReleaseMutex)需要用户方式(User Mode)到内核模式
(Kernel Mode)的转换,在x86处理器上这些转化一般要
发费600个左右的CPU指令周期。
快。
Critical Section本身不是内核对象,相关函数
(EnterCriticalSection,LeaveCriticalSection)
的调用通常都在客户体系内执行,在x86处理器上
一般只应该发费9个左右的CPU指令周期。只有
当想要拿到的锁恰好被别的线程拥有时就会退化
成和Mutex一样,即转化到内核机制,发费600个
左右的CPU指令周期。
能否跨越进程(Process)边界
定义写法
HANDLE hmtx;
CRITICAL_SECTION cs;
初始化写法
hmtx= CreateMutex (NULL, FALSE, NULL);
InitializeCriticalSection(&cs);
结束清除写法
CloseHandle(hmtx);
DeleteCriticalSection(&cs);
无限期等待的写法
WaitForSingleObject (hmtx, INFINITE);
EnterCriticalSection(&cs);
0等待(状态检测)的写法
WaitForSingleObject (hmtx, 0);
TryEnterCriticalSection(&cs);
任意时间等待的写法
WaitForSingleObject (hmtx, dwMilliseconds);
锁释放的写法
ReleaseMutex(hmtx);
LeaveCriticalSection(&cs);
能否被一道用于等待其它内核对象
可以(使用WaitForMultipleObjects,
WaitForMultipleObjectsEx,
MsgWaitForMultipleObjects,
MsgWaitForMultipleObjectsEx等等)
当拥有锁的线程死亡时
Mutex变成abandoned状态,其他的期待线程可以获得锁。
Critical Section的状态不可知(undefined),
以后的动作就不能保证了。
自己会不会锁住自己
不会(对已获取的Mutex,重复读取WaitForSingleObject不会
锁住自己。但最终你别忘了要调用同样次数的
ReleaseMutex)
不会(对已获取的Critical Section,重复调用
EnterCriticalSection不会锁住自己。但最终
你别忘了要调用同样次数的
LeaveCriticalSection)
下面是一些补充:
l请先检查你的设计,把不必要的全局或共享对象改为局部对象。全局的东西越少,出问题的或许就越小。
l每次你使用EnterCriticalSection时,请不要忘了在函数的所有可能返回的地方都加上LeaveCriticalSection。对于Mutex也相同。若你把这个问题和Win32 structured exception或C++ exception一起考虑ccriticalsection 调用 2次,你会看到难题并不是那么简洁。自定义一个封装类也许是一种解决方案,以Critical Section为例的代码如下所示:
class csholder
{
CRITICAL_SECTION *cs;
public:
csholder(CRITICAL_SECTION *c): cs(c)
{ EnterCriticalSection(cs); }
~csholder() { LeaveCriticalSection(cs); }
};
CRITICAL_SECTION some_cs;
void foo()
{
// ...
csholder hold_some(&some_cs);
// ... CS protected code here
// at return or if an exception happens
// hold_some's destructor is automatically called
}
l按照你的互斥范围需求的不同ccriticalsection 调用 2次,把Mutex或Critical Section定义为类的成员函数,或者静态类变量。
l若你想限制访问的全局变量只有一个而且类型非常简单(比如是LONG或PVOID型),你也可以使用InterlockedXXX系列数组来保证一个线程写多个线程读。
Demo程序
#include <Windows.h>
#include <iostream>
using namespace std;
int index = 0;
// 临界区结构对象
CRITICAL_SECTION g_cs;
HANDLE hMutex = NULL;
void changeMe()
{
cout << index++ << endl;
}
void changeMe2()
{
cout << index++ << endl;
}
void changeMe3()
{
cout << index++ << endl;
}
DWORD WINAPI th1(LPVOID lpParameter)
{
while(1)
{
Sleep(1600);//sleep 1.6 s
// 进入临界区
EnterCriticalSection(&g_cs);
// 等待互斥对象通知
//WaitForSingleObject(hMutex, INFINITE);
// 对共享资源进行写入操作
//cout << "a" << index++ << endl;
changeMe();
changeMe2();
changeMe3();
// 释放互斥对象
//ReleaseMutex(hMutex);
// 离开临界区
LeaveCriticalSection(&g_cs);
}
return 0;
}
DWORD WINAPI th2(LPVOID lpParameter)
{
while(1)
{
Sleep(2000);//sleep 2 s
// 进入临界区
EnterCriticalSection(&g_cs);
// 等待互斥对象通知
//WaitForSingleObject(hMutex, INFINITE);
//cout << "b" << index++ << endl;
changeMe();
changeMe2();
changeMe3();
// 释放互斥对象
//ReleaseMutex(hMutex);
// 离开临界区
LeaveCriticalSection(&g_cs);
}
return 0;
}
int main(int argc, char* argv[])
{
// 创建互斥对象
//hMutex = CreateMutex(NULL, TRUE, NULL);
// 初始化临界区
InitializeCriticalSection(&g_cs);
HANDLE hThread1;
HANDLE hThread2;
hThread1 = CreateThread(NULL, 0, th1, NULL, 0, NULL);
hThread2 = CreateThread(NULL, 0, th2, NULL, 0, NULL);
int k;
cin >> k;
printf("Hello World!\n");
return 0;
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-121282-1.html
就放在支付宝里的余额宝已比银行划算
以民用为主