一、多線程帶互斥量的靜態單例:
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