C++多線程編程入門之經典執行個體

來源:互聯網
上載者:User

標籤:lfs   參數傳遞   null   security   .com   news   soft   pac   span   

原文:http://blog.csdn.net/zhang_sinner/article/details/42921397

 

多線程在編程中有相當重要的地位,我們在實際開發時或者找工作面試時總能遇到多線程的問題,對多線程的理解程度從一個側面反映了程式員的編程水平。

       其實C++語言本身並沒有提供多線程機制,但Windows系統為我們提供了相關API,我們可以使用它們來進行多線程編程。本文就以執行個體的形式講解多線程編程的知識。

       建立線程的API函數

C++代碼
  1. HANDLE CreateThread(   
  2.   __in   SEC_ATTRS    
  3.             SecurityAttributes,   
  4.   __in   ULONG    
  5.             StackSize,        // initial stack size   
  6.   __in   SEC_THREAD_START    
  7.             StartFunction,    // thread function   
  8.   __in   PVOID    
  9.             ThreadParameter,  // thread argument
  10.   __in   ULONG    
  11.             CreationFlags,    // creation option   
  12.   __out  PULONG    
  13.             ThreadId          // thread identifier   
  14. );  

       在這裡我們只用到了第三個和第四個參數,第三個參數傳遞了一個函數的地址,也是我們要指定的新的線程,第四個參數是傳給新線程的參數指標。

       多線程編程執行個體1:

C++代碼
  1. #include <iostream>   
  2. #include <windows.h>   
  3. using namespace std;   
  4.   
  5. DWORD WINAPI Fun(LPVOID lpParamter)   
  6. {   
  7.       while(1) { cout<<"Fun display!"<<endl; }   
  8. }   
  9.   
  10. int main()   
  11. {   
  12.     HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);   
  13.     CloseHandle(hThread);   
  14.     while(1) { cout<<"main display!"<<endl;  }   
  15.     return 0;   
  16. }  

       我們可以看到主線程(main函數)和我們自己的線程(Fun函數)是隨機地交替執行的,但是兩個線程輸出太快,使我們很難看清楚,我們可以使用函數Sleep來暫停線程的執行。

C++代碼
  1. VOID WINAPI Sleep(   
  2.   __in  DWORD dwMilliseconds   
  3. );  

       dwMilliseconds表示千分之一秒,所以 Sleep(1000); 表示暫停1秒。

       多線程編程執行個體2:

C++代碼
  1. #include <iostream>   
  2. #include <windows.h>   
  3. using namespace std;   
  4.   
  5. DWORD WINAPI Fun(LPVOID lpParamter)   
  6. {       
  7.       while(1) { cout<<"Fun display!"<<endl; Sleep(1000);}   
  8. }   
  9.   
  10. int main()   
  11. {   
  12.       HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);   
  13.       CloseHandle(hThread);   
  14.       while(1) { cout<<"main display!"<<endl;  Sleep(2000);}   
  15.       return 0;   
  16. }  

       執行上述代碼,這次我們可以清楚地看到在螢幕上交錯地輸出Fun display!和main display!,我們發現這兩個函數確實是並發啟動並執行,細心的讀者可能會發現我們的程式是每當Fun函數和main函數輸出內容後就會輸出換行,但是我們看到的確是有的時候程式輸出換行了,有的時候確沒有輸出換行,甚至有的時候是輸出兩個換行。這是怎麼回事?下面我們把程式改一下看看。

 

        多線程編程執行個體3:

C++代碼
  1. #include <iostream>   
  2. #include <windows.h>   
  3. using namespace std;   
  4.   
  5. DWORD WINAPI Fun(LPVOID lpParamter)   
  6. {   
  7.       while(1) { cout<<"Fun display!\n"; Sleep(1000);}   
  8. }   
  9.   
  10. int main()   
  11. {   
  12.       HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);   
  13.       CloseHandle(hThread);   
  14.       while(1) { cout<<"main display!\n";  Sleep(2000);}   
  15.       return 0;   
  16. }  

       我們再次運行這個程式,我們發現這時候正如我們預期的,正確地輸出了我們想要輸出的內容並且格式也是正確的。下面我就來講一下此前我們的程式為什麼沒有正確的運行。多線程的程式時並發地啟動並執行,多個線程之間如果公用了一些資源的話,我們並不能保證這些資源都能正確地被利用,因為這個時候資源並不是獨佔的,下面舉個例子吧。

       多線程編程執行個體4:

       假如有一個資源 int a = 3

       有一個線程函數 selfAdd() 該函數是使 a += a;

       又有一個線程函數 selfSub() 該函數是使 a -= a;

       我們假設上面兩個線程正在並發欲行,如果selfAdd在執行的時候,我們的目的是想讓a編程6,但此時selfSub得到了啟動並執行機會,所以a變成了0,等到selfAdd的到執行的機會後,a += a ,但是此時a確是0,並沒有如我們所預期的那樣的到6。

       我們回到前面執行個體2,在這裡,我們可以把螢幕看成是一個資源,這個資源被兩個線程所共用,加入當Fun函數輸出了Fun display!後,將要輸出endl(也就是清空緩衝區並換行,在這裡我們可以不用理解什麼事緩衝區),但此時main函數確得到了啟動並執行機會,此時Fun函數還沒有來得及輸出換行就把CPU讓給了main函數,而這時main函數就直接在Fun display!後輸出main display!,至於為什麼有的時候程式會連續輸出兩個換行,讀者可以採用同樣的分析方法來分析,在這裡我就不多講了,留給讀者自己思考了。

       那麼為什麼我們把執行個體2改成執行個體3就可以正確的運行呢?原因在於,多個線程雖然是並發啟動並執行,但是有一些操作是必須一氣呵成的,不允許打斷的,所以我們看到執行個體2和執行個體3的運行結果是不一樣的。

       那麼,是不是執行個體2的代碼我們就不可以讓它正確的運行呢?答案當然是否,下面我就來講一下怎樣才能讓執行個體2的代碼可以正確運行。這涉及到多線程的同步問題。對於一個資源被多個線程共用會導致程式的混亂,我們的解決方案是只允許一個線程擁有對共用資源的獨佔,這樣就能夠解決上面的問題了。

C++代碼
  1. HANDLE CreateMutex(      
  2.     LPSECURITY_ATTRIBUTES lpMutexAttributes,       
  3.     BOOL bInitialOwner,                       // initial owner      
  4.     LPCTSTR lpName                            // object name      
  5. );   

       該函數用於創造一個獨佔資源,第一個參數我們沒有使用,可以設為NULL,第二個參數指定該資源初始是否歸屬建立它的進程,第三個參數指定資源的名稱。

C++代碼
  1. HANDLE hMutex = CreateMutex(NULL,TRUE,"screen");   

       這條語句創造了一個名為screen並且歸屬於建立它的進程的資源。

C++代碼
  1. BOOL ReleaseMutex(   
  2.     HANDLE hMutex   // handle to mutex   
  3. );  

       該函數用於釋放一個獨佔資源,進程一旦釋放該資源,該資源就不再屬於它了,如果還要用到,需要重新申請得到該資源。申請資源的函數如下:

C++代碼
  1. DWORD WaitForSingleObject(   
  2.     HANDLE hHandle,        // handle to object   
  3.     DWORD dwMilliseconds   // time-out interval   
  4. );  

       第一個參數指定所申請的資源的控制代碼,第二個參數一般指定為INFINITE,表示如果沒有申請到資源就一直等待該資源,如果指定為0,表示一旦得不到資源就返回,也可以具體地指定等待多久才返回,單位是千分之一秒。好了,該到我們來解決執行個體2的問題的時候了,我們可以把執行個體2做一些修改,如下面的執行個體。

       多線程編程執行個體5:

C++代碼
  1. #include <iostream>   
  2. #include <windows.h>   
  3. using namespace std;   
  4.   
  5. HANDLE hMutex;   
  6.   
  7. DWORD WINAPI Fun(LPVOID lpParamter)   
  8. {   
  9.        while(1) {    
  10.                  WaitForSingleObject(hMutex, INFINITE);   
  11.                  cout<<"Fun display!"<<endl;    
  12.                  Sleep(1000);   
  13.                  ReleaseMutex(hMutex);   
  14.         }   
  15. }   
  16.   
  17. int main()   
  18. {   
  19.       HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);   
  20.       hMutex = CreateMutex(NULL, FALSE, "screen");   
  21.       CloseHandle(hThread);   
  22.       while(1) {   
  23.                WaitForSingleObject(hMutex, INFINITE);   
  24.                cout<<"main display!"<<endl;     
  25.                Sleep(2000);   
  26.                ReleaseMutex(hMutex);   
  27.       }   
  28.   
  29.       return 0;   
  30. }  

       運行此代碼會得到我們預期的輸出內容。

C++多線程編程入門之經典執行個體

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.