1. 程式人生 > 其它 >C語言 memcpy 和 strcpy 函式區別 - C語言零基礎入門教程

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 類。