C++互斥锁在多线程单例和多进程中的应用


一、多线程带互斥量的静态单例:

 1 #include <iostream>
 2 #include <thread>         // std::thread 
 3 #include <mutex>          // std::mutex
 4 using namespace std;
 5  
 6 /*用互斥量构建一个枷锁类*/
 7 class Lock{
 8 private:
 9     mutex mtx;//互斥量
10 public:
11     void lock(){ mtx.lock(); }//加锁
12     void unlock(){ mtx.unlock(); }//解锁
13 };
14 /*静态单例*/
15 class singleton{
16 private:
17     int _value;//测试用值,静态单例在哪个线程中被第一次获取,_value的值就是哪个线程的id
18     singleton(int value);//构造函数
19     singleton(const singleton &);//复制构造函数
20     singleton& operator=(const singleton &);//赋值构造函数
21 public:
22     static Lock* Locker;//声明一个枷锁指针
23     static singleton* Instance;//声明一个对象
24  
25     static singleton* getInstance(int thread_id);//声明获取单例的函数
26     int getValue();//获取测试值
27     ~singleton();//析构函数
28 };
29  
30 singleton::singleton(int value) :_value(value){}//构造函数
31 singleton::singleton(const singleton &){}//复制构造函数
32 singleton& singleton::operator=(const singleton &){ return *this; }//赋值构造函数
33 singleton::~singleton(){}//析构函数
34  
35 Lock* singleton::Locker = new Lock();//初始化静态单例中的枷锁
36 singleton* singleton::Instance = NULL;//初始化静态单例
37  
38 singleton* singleton::getInstance(int thread_id){//定义获取单例的函数
39     if (Instance == NULL){//由于加锁比较费事,所以先判断一次
40         Locker->lock();
41         if (Instance == NULL){
42             Instance = new singleton(thread_id);//初始化静态单例,参数为 线程的id
43         }
44         Locker->unlock();
45     }
46     return Instance;
47 }
48 int singleton::getValue(){//获取测试值
49     return _value;
50 }
51  
52 mutex myMtx;//为了防止多个线程争夺 标准输出资源而设置的互斥量
53 void print_thread_id(int thread_id){//线程函数
54     singleton* Instance = singleton::getInstance(thread_id);//获取静态单例
55     myMtx.lock();
56     cout << "thread_id: " << thread_id << endl;
57     cout << "Instance is Created in thread: " << Instance->getValue() << endl;
58     myMtx.unlock();
59 }
60  
61 int main(){
62     thread threads[2];//两个线程
63     int i;
64     for (i = 0; i < 2; ++i)
65         threads[i] = thread(print_thread_id, i);//启动线程
66  
67     for (auto& th : threads) th.join();//等线程结束
68     return 0;
69 }

 

二、多进程中的互斥锁应用(命名互斥锁)

 1 HANDLE hMutex = CreateMutex(NULL, false, "Process");
 2          if (GetLastError() == ERROR_ALREADY_EXISTS)
 3          {
 4             CloseHandle(hMutex);
 5             MessageBox(Application->Handle, "程序已经在运行中,不能重复启动!", "提示", MB_OK +MB_ICONWARNING);
 6             Application->Terminate();
 7             return 0;
 8          }
 9          Application->CreateForm(__classid(TForm1), &Form1);
10 
11         主要使用到CreateMutex()函数和GetLastError()以及一个常量ERROR_ALREADY_EXISTS.
12 
13         当然, 你的程序有窗体的话, 还可以使用FindWindow(). 
14         void *handle = FindWindow(NULL, WindowName.c_str()); 
15         if (handle!=NULL)
16             return 0; 

进程的互斥运行

  正常情况下,一个进程的运行一般是不会影响到其他正在运行的进程的。但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的,而且此类程序通常也不允许运行同一个程序的多个实例。这就引出了进程互斥的问题。

  实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识实例已经存在的标记。此后再创建进程时将会通过该标记而知晓其实例已经存在,从而保证进程在系统中只能存在一个实例。具体可以采取内存映射文件、有名事件量、有名互斥量以及全局共享变量等多种方法来实现。下面就分别对其中具有代表性的有名互斥量和全局共享变量这两种方法进行介绍:

 1 // 创建互斥量
 2 HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
 3 // 检查错误代码
 4 if (GetLastError() == ERROR_ALREADY_EXISTS) {
 5  // 如果已有互斥量存在则释放句柄并复位互斥量
 6  CloseHandle(m_hMutex);
 7  m_hMutex = NULL;
 8  // 程序退出
 9  return FALSE;
10 }

  上面这段代码演示了有名互斥量在进程互斥中的用法。代码的核心是CreateMutex()对有名互斥量的创建。CreateMutex()函数可用来创建一个有名或无名的互斥量对象,其函数原型为:

1 HANDLE CreateMutex(
2  LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针,指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承
3  BOOL bInitialOwner, // 初始化互斥对象的所有者,布尔类型,决定互斥体的创建者是否为拥有者
4  LPCTSTR lpName // 指向互斥对象名的指针,指向互斥体名字字符串的指针。互斥体可以有名字

   如果函数成功执行,将返回一个互斥量对象的句柄。如果在CreateMutex()执行前已经存在有相同名字的互斥量,函数将返回这个已经存在互斥量的句柄,并且可以通过GetLastError()得到错误代码ERROR_ALREADY_EXIST。可见,通过对错误代码ERROR_ALREADY_EXIST的检测可以实现CreateMutex()对进程的互斥。

        建立互斥体,用来同步。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。互斥体的好处是可以在进程间共享

心得体会:
    CreateMutex() 用于有独占要求的程序 (在其进程运行期间不允许其他使用此端口设备的程序运行,或不允许同名程序运行)。如有同名程序运行,则通过 GetLastError()得到错误代码 ERROR_ALREADY_EXIST。

刚才又执行了下得出的结果(程序名samp)
       一般情况下:一进入调试阶段,进程管理器中就出现了samp进程,执行到CreateMutex时返回进程句柄,执行到if(GetLastError() == ERROR_ALREADY_EXISTS ) 进行判断时,跳过不执行if中的内容,所以表示没有互斥。
       调试之前先运行debug中的samp.exe再调试:一进入调试阶段,进程管理器中就出现了两个samp进程,执行到CreateMutex时返回进程句柄,执行到if(GetLastError() == ERROR_ALREADY_EXISTS ) 进行判断时,执行if中的内容,表示有互斥。

转自:http://blog.csdn.net/laura0502/archive/2009/01/20/3838732.aspx


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM