VC下線程同步的三種方法(互斥、事件、臨界區)

首選使用臨界區對象,主要原因是使用簡單。
EnterCriticalSection()函數等候指定的危險區段對象的所有權。當調用的線程被允許所有權時,函數返回。
EnterCriticalSection (),一個單獨進程的線程可以使用一個危險區段對象作爲相互-排除同步。 進程負責分配被一個危險區段對象使用的內存, 它藉由聲明一個CRITICAL_SECTION類型 的變量實現。在使用一個危險區段之前,進程的一些線程必須調用 InitializeCriticalSection 函數設定對象的初值.
爲了要使互斥的訪問被共享的資源,每個線程調用EnterCriticalSection 或者 TryEnterCriticalSection 功能,在執行訪問被保護資源的任何代碼段之前,請求危險區段的所有權。

#include <windows.h>

#include <iostream>

 

using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

int tickets=100;

 

CRITICAL_SECTION g_csA;

CRITICAL_SECTION g_csB;

 

void main()

{

       HANDLE hThread1;

       HANDLE hThread2;

       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

       CloseHandle(hThread1);

       CloseHandle(hThread2);

       InitializeCriticalSection(&g_csA);

       InitializeCriticalSection(&g_csB);

       Sleep(40000);

       DeleteCriticalSection(&g_csA);

       DeleteCriticalSection(&g_csB);

}

 

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

       while (TRUE)

       {

              EnterCriticalSection(&g_csA);

              Sleep(1);

              //EnterCriticalSection(&g_csB);//臨界區的同步和互鎖

              if (tickets>0)

              {

                     Sleep(1);

                     cout<<"Thread1 sell ticket :"<<tickets--<<endl;

                     //LeaveCriticalSection(&g_csB);

                     LeaveCriticalSection(&g_csA);

              }

              else

              {

                     //LeaveCriticalSection(&g_csB);

                     LeaveCriticalSection(&g_csA);

                     break;

              }

       }

       return 0;

}

 

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

       while (TRUE)

       {

              EnterCriticalSection(&g_csB);

              Sleep(1);

              EnterCriticalSection(&g_csA);

              if (tickets>0)

              {

                     Sleep(1);

                     cout<<"Thread2 sell ticket :"<<tickets--<<endl;

                     LeaveCriticalSection(&g_csA);

                     LeaveCriticalSection(&g_csB);

              }

              else

              {

                     LeaveCriticalSection(&g_csA);

                     LeaveCriticalSection(&g_csB);

                     break;

              }

       }

       return 0;

}


--------------------------------------------------------------------------------

 

二、使用互斥對象
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
如果時間是有信號狀態返回WAIT_OBJECT_0,如果時間超過dwMilliseconds值但時間事件還是無信號狀態則返回WAIT_TIMEOUT
WaitForSingleObject函數用來檢測hHandle事件的信號狀態,當函數的執行時間超過dwMilliseconds就返回,但如果參數dwMilliseconds爲INFINITE時函數將直到相應時間事件變成有信號狀態才返回,否則就一直等待下去,直到WaitForSingleObject有返回直才執行後面的代碼。

#include <windows.h>

#include <iostream>

using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

int index =0;

int tickets=100;

HANDLE hMutex;

 

void main()

{

       HANDLE hThread1;

       HANDLE hThread2;

       //創建線程

       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

       CloseHandle(hThread1);

       CloseHandle(hThread2);

       //**************************************************************

       //保證應用程序只有一個實例運行,創建一個命名的互斥對象.

       hMutex=CreateMutex(NULL,TRUE,LPCTSTR("tickets"));

       //創建時主線程擁有該互斥對象,互斥對象的線程ID爲主線程的ID,同時將該互斥對象內部計數器置爲1

       if (hMutex)

       {

              if (ERROR_ALREADY_EXISTS==GetLastError())

              {

                     cout<<"only one instance can run!"<<endl;

                     //Sleep(40000);

                     return;

              }

       }

       //**************************************************************

       WaitForSingleObject(hMutex,INFINITE);

       //使用該函數請求互斥對象時,雖說該對象處於無信號狀態,但因爲請求的線程ID和該互斥對象所有者的線程ID是相同的.所以仍然

       //可以請求到這 個互斥對象,於是該互斥對象內部計數器加1,內部計數器的值爲2. 意思是有兩個等待動作

       ReleaseMutex(hMutex);//釋放一次互斥對象,該互斥對象內部計數器的值遞減1,操作系統不會將這個互斥對象變爲已通知狀態.

       ReleaseMutex(hMutex);//釋放一次互斥對象,該互斥對象內部計數器的值爲0,同時將該對象設置爲已通知狀態.

       //對於互斥對象來說,誰擁有誰釋放

       Sleep(40000);

}

 

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

       while (TRUE)

       {

              WaitForSingleObject(hMutex,INFINITE);//等待互斥對象有信號

              if (tickets>0)

              {

                     Sleep(1);

                     cout<<"thread1 sell ticket :"<<tickets--<<endl;

               }

              else

                     break;

              ReleaseMutex(hMutex);//設置該互斥對象的線程ID爲0,並且將該對象設置爲有信號狀態

       }

       return 0;

}

 

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

       while (TRUE)

       {

              WaitForSingleObject(hMutex,INFINITE);

              if (tickets>0)

              {

                     Sleep(1);

                     cout<<"thread2 sell ticket :"<<tickets--<<endl;

              }

              else

                     break;

              ReleaseMutex(hMutex);

       }

       return 0;

}


--------------------------------------------------------------------------------


三、使用事件對象
HANDLE     CreateEvent(  
        LPSECURITY_ATTRIBUTES     lpEventAttributes,           //     SD  
        BOOL     bManualReset,                                                 //     reset     type  
        BOOL     bInitialState,                                                     //     initial     state  
        LPCTSTR     lpName                                                      //     object     name  
    );  
    該函數創建一個Event同步對象,並返回該對象的Handle  
   
    lpEventAttributes     一般爲NULL  
    bManualReset               創建的Event是自動復位還是人工復位    &nbsp;,如果true,人工復位,  
    一旦該Event被設置爲有信號,則它一直會等到ResetEvent()API被調用時纔會恢復  
    爲無信號.     如果爲false,Event被設置爲有信號,則當有一個wait到它的Thread時,  
    該Event就會自動復位,變成無信號.  
    bInitialState             初始狀態,true,有信號,false無信號  
    lpName                           Event對象名  
   
    一個Event被創建以後,可以用OpenEvent()API來獲得它的Handle,用CloseHandle()  
    來關閉它,用SetEvent()或PulseEvent()來設置它使其有信號,用ResetEvent()  
    來使其無信號,用WaitForSingleObject()或WaitForMultipleObjects()來等待  
    其變爲有信號.  
   
    PulseEvent()是一個比較有意思的使用方法,正如這個API的名字,它使一個Event  
    對象的狀態發生一次脈衝變化,從無信號變成有信號再變成無信號,而整個操作是原子的.  
    對自動復位的Event對象,它僅釋放第一個等到該事件的thread(如果有),而對於  
    人工復位的Event對象,它釋放所有等待的thread. 

 

#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;

 

void main()
{
       HANDLE hThread1;
       HANDLE hThread2;
       //**************************************************
       //創建一個命名的自動重置事件內核對象
       g_hEvent=CreateEvent(NULL,FALSE,FALSE,LPCTSTR("tickets"));
       if (g_hEvent)
       {
              if (ERROR_ALREADY_EXISTS==GetLastError())
              {
                     cout<<"only one instance can run!"<<endl;
                     return;
              }
       }
       //**************************************************
       SetEvent(g_hEvent);
       //創建線程
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

       Sleep(40000);
       //關閉事件對象句柄
       CloseHandle(g_hEvent);
}

 

DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
       while (TRUE)
       {
              WaitForSingleObject(g_hEvent,INFINITE);
              //ResetEvent(g_hEvent);
              if (tickets>0)
              {
                     Sleep(1);
                     cout<<"thread1 sell ticket :"<<tickets--<<endl;
                     SetEvent(g_hEvent);
              }
              else
              {
                     SetEvent(g_hEvent);
                     break;
              }
       }
       return 0;
}

 

DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
       while (TRUE)
         {
              WaitForSingleObject(g_hEvent,INFINITE);
              //ResetEvent(g_hEvent);
              if (tickets>0)
              {
                     cout<<"Thread2 sell ticket :"<<tickets--<<endl;
                     SetEvent(g_hEvent);
              }
              else
              {
                     SetEvent(g_hEvent);
                     break;
              }
          }
            return 0;
}

文章出處:飛諾網(www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppsl/200864/121416.html

發佈了0 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章