C語言 memcpy 和 strcpy 函式區別 - C語言零基礎入門教程
一、並行和併發:
並行:多個任務在同一時刻同時執行。
併發:多個任務順序執行,不是同時。
二、程序和執行緒:
程序是系統分配資源的最小單位,執行緒是cpu執行任務的最小單位。
對於單核CPU而言,同一時刻只能執行一個執行緒。每隔一定時間會切換執行緒(可能是同一個程序的執行緒,也可能是另外一個程序的執行緒,如果是其它程序的執行緒)。
在單核CPU上實現的多執行緒其實是“假”的多執行緒,CPU同一時刻只能執行,只不過CPU切換任務的速度很快,所以你感覺是同時執行了多個任務,即實現了多執行緒。
在單核CPU上,無論是執行緒還是程序,都只能併發執行,多核CUP上有可能實現並行執行。
三、多執行緒
下面用一個最簡單的多執行緒例子說明。
C++11之前建立多執行緒的函式有2個:_beginthreadex、CreateThread
前者是C++庫函式,後者是Windows API。我們使用_beginthreadex。
int main() { for (int i = 0; i < 5; i++) { cout<<"1234567890------"<< i<<endl; } system("pause"); return 0; }
上述程式只有一個程序,mian函式就是這個程序的主執行緒,列印結果,是順序執行,順序列印。
現在給它新增一個子執行緒:
//執行緒函式 unsigned __stdcall ThreadProc( void * lpParameter) { int* p = (int*)lpParameter; for (int i = 0; i < *p; i++) { cout<<"abcdefghij------"<< i<<endl; } return 0; } int main() { unsigned nThreadID = 0 ; int n = 5; HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadProc, (LPVOID)&n, 0, &nThreadID ); CloseHandle(hThread); for (int i = 0; i < 5; i++) { cout<<"1234567890------"<< i<<endl; } system("pause"); return 0; }
列印結果如下。可以看到,雖然程式碼中,主執行緒的列印部分是寫在子執行緒的後面的,但結果是主執行緒的列印內容先出來了。
我們再在主執行緒和子執行緒中分別加上一個Sleep,如下:
//執行緒函式 unsigned __stdcall ThreadProc( void * lpParameter) { int* p = (int*)lpParameter; for (int i = 0; i < *p; i++) { Sleep(10); cout<<"abcdefghij------"<< i<<endl; } return 0; } int main() { unsigned nThreadID = 0 ; int n = 5; HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadProc, (LPVOID)&n, 0, &nThreadID ); CloseHandle(hThread); for (int i = 0; i < 5; i++) { Sleep(10); cout<<"1234567890------"<< i<<endl; } system("pause"); return 0; }
列印結果如下。可以發現順序又變了,而且相互影響,沒有規律。
四、執行緒安全
上面的最後一個例子,可以發現最後的列印結果沒有規律,不可預見,就稱之為執行緒不安全,在實際專案中這樣簡單地使用多執行緒程式碼肯定是不行的。
執行緒不安全的原因通常是共享了資源,解決方法是使用加鎖來規避。
鎖的核心功能是多個執行緒訪問同一個資源,保證同一時刻只有一個執行緒能使用該資源,對該資源有獨佔訪問權。
C++ 11 封裝了類mutex,幫我們完成,直接用就行了。
五、使用鎖mutex
mutex mutex1 ; unsigned __stdcall ThreadProc( void * lpParameter) { int* p = (int*)lpParameter; for (int i = 0; i < *p; i++) { mutex1.lock(); Sleep(10); cout<<"abcdefghij------"<< i<<endl; mutex1.unlock(); } return 0; } int main() { unsigned nThreadID = 0 ; int n = 5; HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadProc, (LPVOID)&n, 0, &nThreadID ); CloseHandle(hThread); for (int i = 0; i < 5; i++) { mutex1.lock(); Sleep(10); cout<<"1234567890------"<< i<<endl; mutex1.unlock(); } system("pause"); return 0; }
結果如下:
其實 最後一行system("pause"); 也使用了cout,完整的寫法應該在它的前後也加上鎖。
否則,如果將Sleep的引數改大,比如我的電腦上,將其改為Sleep(5000),可能出現如下結果:
六、使用C++11開發多執行緒
C++11不僅僅有執行緒鎖的封裝,也提供了執行緒的封裝 std::thread。
在C++11之前,我們只能使用windows的api來實現多執行緒,現在拋棄前面建立多執行緒的那一套吧,直接使用封裝好的 std::thread 類。