程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 互斥對象、事件對象、關鍵代碼段

互斥對象、事件對象、關鍵代碼段

編輯:C++入門知識

最近復習了一下多線程的知識


作用差不多,側重點不一樣

臨界區:  共享資源
互斥對象  線程間的同步
事件對象:一般用在比較復雜的地方,能夠傳遞一些信息


下面是互斥對象、事件對象和關鍵代碼段的比較:

1互斥對象


[cpp]
#include <iostream>  
#include <windows.h>  
using namespace std; 
 
// 聲明兩個線程函數  
DWORD WINAPI ThreadProc1( 
                        LPVOID lpParameter   // thread data  
                        ); 
 
DWORD WINAPI ThreadProc2( 
                        LPVOID lpParameter   // thread data  
                        ); 
 
// 全局票數  
int gTicket = 100; 
 
// 互斥對象  
HANDLE hMutex; 
 
int main() 

    // 創建兩個線程句柄  
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); 
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); 
 
    // 創建互斥對象  
    hMutex = CreateMutex(NULL, false, NULL); 
 
    // 關閉兩個線程句柄  
    CloseHandle(hThread1); 
    CloseHandle(hThread2); 
 
    // 主線程睡4秒,方便兩個線程函數能夠獲取CPU時間片  
    Sleep(4000); 
 
    system("pause"); 
    return 0; 

 
// 定義兩個線程函數  
DWORD WINAPI ThreadProc1(LPVOID lpParameter ) 

    while(true) 
    { 
        WaitForSingleObject(hMutex, INFINITE); 
        if(gTicket > 0) 
        { 
            cout<<"thread1 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        ReleaseMutex(hMutex); 
    } 
    return 0; 

 
DWORD WINAPI ThreadProc2(LPVOID lpParameter ) 

    while(true) 
    { 
        WaitForSingleObject(hMutex, INFINITE); 
        if(gTicket > 0) 
        { 
            cout<<"thread2 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        ReleaseMutex(hMutex); 
    } 
    return 0; 

#include <iostream>
#include <windows.h>
using namespace std;

// 聲明兩個線程函數
DWORD WINAPI ThreadProc1(
      LPVOID lpParameter   // thread data
      );

DWORD WINAPI ThreadProc2(
      LPVOID lpParameter   // thread data
      );

// 全局票數
int gTicket = 100;

// 互斥對象
HANDLE hMutex;

int main()
{
 // 創建兩個線程句柄
 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
 HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

 // 創建互斥對象
 hMutex = CreateMutex(NULL, false, NULL);

 // 關閉兩個線程句柄
 CloseHandle(hThread1);
 CloseHandle(hThread2);

 // 主線程睡4秒,方便兩個線程函數能夠獲取CPU時間片
 Sleep(4000);

 system("pause");
 return 0;
}

// 定義兩個線程函數
DWORD WINAPI ThreadProc1(LPVOID lpParameter )
{
 while(true)
 {
  WaitForSingleObject(hMutex, INFINITE);
  if(gTicket > 0)
  {
   cout<<"thread1 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  ReleaseMutex(hMutex);
 }
 return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter )
{
 while(true)
 {
  WaitForSingleObject(hMutex, INFINITE);
  if(gTicket > 0)
  {
   cout<<"thread2 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  ReleaseMutex(hMutex);
 }
 return 0;
}

 


2事件對象

[cpp]
#include <Windows.h>  
#include <iostream>  
using namespace std; 
 
// 聲明兩個線程函數  
DWORD WINAPI ThreadProc1( 
                         LPVOID lpParameter   // thread data  
                         ); 
 
DWORD WINAPI ThreadProc2( 
                         LPVOID lpParameter   // thread data  
                         ); 
 
// 全局變量  
int gTicket = 100; 
 
// 事件對象  
HANDLE hEvent; 
 
int main() 

    // 創建兩個線程句柄  
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); 
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); 
 
    // 創建時間對象  
    hEvent = CreateEvent(NULL, false, true, NULL); 
 
    // 關閉兩個線程句柄  
    CloseHandle(hThread1); 
    CloseHandle(hThread2); 
 
    // 主線程睡4秒,讓別的線程函數有機會獲得CPU時間片  
    Sleep(4000); 
 
 
    system("pause"); 
    return 0; 

 
 
// 定義兩個線程函數  
DWORD WINAPI ThreadProc1(LPVOID lpParameter ) 

    while(true) 
    { 
        WaitForSingleObject(hEvent, INFINITE);       
        if(gTicket > 0) 
        { 
            cout<<"thread1 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        SetEvent(hEvent); 
    } 
    return 0; 

 
DWORD WINAPI ThreadProc2(LPVOID lpParameter ) 

    while(true) 
    { 
        WaitForSingleObject(hEvent, INFINITE); 
        if(gTicket > 0) 
        { 
            cout<<"thread2 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        SetEvent(hEvent); 
    } 
    return 0; 

#include <Windows.h>
#include <iostream>
using namespace std;

// 聲明兩個線程函數
DWORD WINAPI ThreadProc1(
       LPVOID lpParameter   // thread data
       );

DWORD WINAPI ThreadProc2(
       LPVOID lpParameter   // thread data
       );

// 全局變量
int gTicket = 100;

// 事件對象
HANDLE hEvent;

int main()
{
 // 創建兩個線程句柄
 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
 HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

 // 創建時間對象
 hEvent = CreateEvent(NULL, false, true, NULL);

 // 關閉兩個線程句柄
 CloseHandle(hThread1);
 CloseHandle(hThread2);

 // 主線程睡4秒,讓別的線程函數有機會獲得CPU時間片
 Sleep(4000);


 system("pause");
 return 0;
}


// 定義兩個線程函數
DWORD WINAPI ThreadProc1(LPVOID lpParameter )
{
 while(true)
 {
  WaitForSingleObject(hEvent, INFINITE);  
  if(gTicket > 0)
  {
   cout<<"thread1 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  SetEvent(hEvent);
 }
 return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter )
{
 while(true)
 {
  WaitForSingleObject(hEvent, INFINITE);
  if(gTicket > 0)
  {
   cout<<"thread2 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  SetEvent(hEvent);
 }
 return 0;
}
3關鍵代碼段


[cpp]
#include <iostream>  
#include <windows.h>  
using namespace std; 
 
// 聲明兩個線程函數  
DWORD WINAPI ThreadProc1( 
                         LPVOID lpParameter   // thread data  
                         ); 
 
DWORD WINAPI ThreadProc2( 
                         LPVOID lpParameter   // thread data  
                         ); 
 
// 全局票數  
int gTicket = 100; 
 
// 關鍵代碼段  
CRITICAL_SECTION gSection; 
 
 
int main() 

 
    // 初始化關鍵代碼段,必須先於線程的創建  
    InitializeCriticalSection(&gSection); 
 
    // 創建兩個線程句柄  
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); 
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); 
 
    // 關閉兩個線程句柄  
    CloseHandle(hThread1); 
    CloseHandle(hThread2); 
 
    // 主線程sleep 4秒  
    Sleep(4000); 
     
    // 刪除關鍵代碼段  
    DeleteCriticalSection(&gSection); 
 
    system("pause"); 
    return 0; 

 
// 定義兩個線程函數  
DWORD WINAPI ThreadProc1(LPVOID lpParameter ) 

    while(true) 
    { 
        EnterCriticalSection(&gSection);                            // 進入關鍵代碼段  
        if(gTicket > 0) 
        { 
            cout<<"thread1 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        LeaveCriticalSection(&gSection);                            // 離開關鍵代碼段  
    } 
    return 0; 

 
DWORD WINAPI ThreadProc2(LPVOID lpParameter ) 

    while(true) 
    { 
        EnterCriticalSection(&gSection);                            // 進入關鍵代碼段  
        if(gTicket > 0) 
        { 
            cout<<"thread2 sell ticket "<<gTicket--<<endl; 
        } 
        else 
        { 
            break; 
        } 
        LeaveCriticalSection(&gSection);                            // 離開關鍵代碼段  
    } 
    return 0; 

#include <iostream>
#include <windows.h>
using namespace std;

// 聲明兩個線程函數
DWORD WINAPI ThreadProc1(
       LPVOID lpParameter   // thread data
       );

DWORD WINAPI ThreadProc2(
       LPVOID lpParameter   // thread data
       );

// 全局票數
int gTicket = 100;

// 關鍵代碼段
CRITICAL_SECTION gSection;


int main()
{

 // 初始化關鍵代碼段,必須先於線程的創建
 InitializeCriticalSection(&gSection);

 // 創建兩個線程句柄
 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
 HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

 // 關閉兩個線程句柄
 CloseHandle(hThread1);
 CloseHandle(hThread2);

 // 主線程sleep 4秒
 Sleep(4000);
 
 // 刪除關鍵代碼段
 DeleteCriticalSection(&gSection);

 system("pause");
 return 0;
}

// 定義兩個線程函數
DWORD WINAPI ThreadProc1(LPVOID lpParameter )
{
 while(true)
 {
  EnterCriticalSection(&gSection);       // 進入關鍵代碼段
  if(gTicket > 0)
  {
   cout<<"thread1 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  LeaveCriticalSection(&gSection);       // 離開關鍵代碼段
 }
 return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter )
{
 while(true)
 {
  EnterCriticalSection(&gSection);       // 進入關鍵代碼段
  if(gTicket > 0)
  {
   cout<<"thread2 sell ticket "<<gTicket--<<endl;
  }
  else
  {
   break;
  }
  LeaveCriticalSection(&gSection);       // 離開關鍵代碼段
 }
 return 0;
}
程序運行的結果,相信大家都已經很清楚了,但是,前面兩個內核對象(互斥對象、事件對象)的結果有點出乎意料。

以事件對象為例。用斷點調試,竟然發現了這樣的問題。線程1的函數獲取互斥對象的擁有權(並未釋放擁有權),接著切換CPU時間片,進入到了線程2函數的WaitForSingleObject,然後調用了線程2函數的 cout<<"thread2 sell ticket "<<gTicket--<<endl;,這是怎麼一回事呢,線程1函數還未釋放擁有權,線程2函數怎麼還能運行的?

使用互斥對象,顯示的結果有時候會是這樣。百思不得其解。

 

\
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved