C++多线程之使用Mutex和Critical_Section

Mutex和Critical Section都是主要用于限制多线程(Multithread)对全局或共享的变量、对象或内存空间的访问。下面是其主要的异同点(不一样的地方用绿色表示)。ios

 

Mutex多线程

Critical Sectionapp

性能和速度函数

慢。性能

Mutex 是内核对象,相关函数的执行 (WaitForSingleObject,spa

ReleaseMutex)须要用户模式(User Mode)到内核模式.net

(Kernel Mode)的转换,在x86处理器上这种转化通常要线程

发费600个左右的 CPU指令周期。设计

快。code

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一块儿考虑,你会发现问题并非那么简单。自定义一个封装类多是一种解决方案,以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         根据你的互斥范围需求的不一样,把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; } ---------------------  做者:LoveApp_Han  来源:CSDN  原文:https://blog.csdn.net/xdrt81y/article/details/17005235  版权声明:本文为博主原创文章,转载请附上博文连接!

相关文章
相关标签/搜索