1. 程式人生 > 其它 >主執行緒和子執行緒多種情況小探討

主執行緒和子執行緒多種情況小探討

一.背景

今天看了一篇有關volatile在多執行緒中使用的部落格(自己對該部落格的總結:https://i-beta.cnblogs.com/posts/edit;postId=11388620),裡面的例子沒有詳細地進行程式碼實現.自己想要驗證下這個問題,同時練習下多執行緒程式設計的招式,去專門實現了一下.發現真正自己去動手時,頭腦中會湧現出很多的疑問,同時也產生了很多的收穫.

二.程式碼示例

程式碼要實現的功能是每隔一秒對flag_進行判斷,如果flag_被另外的執行緒改為true的話,就會跳出迴圈.

這裡主要是針對主執行緒和子執行緒使用時,嘗試了多種組合,看看都會有怎樣的化學反應.

#include <iostream>
#include <windows.h>

using namespace std;

class Test
{
private:
    volatile bool m_bFlag;
public:
    Test()
    {
        m_bFlag = false;
    }
    void Wait()
    {
        while (!m_bFlag)
        {
            cout << "I'm Sleeping" << endl;
            Sleep(1000);
        }
        cout << "I'm awake" << endl;
    }

    void WakeUp()
    {
        m_bFlag = true;
    }
};

DWORD WINAPI ThreadFun2(void *param)
{
    Test *tThread = (Test *)param;
    tThread->WakeUp();
    return 0;
}

DWORD WINAPI ThreadFun1(void *param)
{
    Test *tThread = (Test *)param;
    tThread->Wait();
    return 0;
}

/*下面實現一個執行緒隔1s進行等待判斷,並且顯式打印出"I'm Sleeping",另一個執行緒去把它的等待結束的過程.並標註下能否實現該需求.*/

//這種情形會一閃而過,因為主執行緒沒有等待子執行緒的過程,主執行緒結束後進程結束,子執行緒也終止了.
//未能實現
int main1()
{
    Test t;
    //建立子執行緒
    HANDLE h = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);
    t.WakeUp();
    return 0;
}

//會造成只執行子執行緒,主執行緒不執行的問題.這個時候我就誤以為是主執行緒和子執行緒不能夠同時運行了,其實這裡是主執行緒使用讓著子執行緒.
//未能實現
int main2()
{
    Test t;
    //建立子執行緒
    HANDLE h = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);
    WaitForSingleObject(h, INFINITE);    //INFINITE表示等待子執行緒結束後,才會走下面的邏輯.這裡子執行緒的死迴圈無法打破,會一直阻塞在這裡.
    t.WakeUp();                                                    
    return 0;
}


//這種情況能夠保證子執行緒執行3s,然後把它WakeUp.
//能實現
int main3()
{
    Test t;
    //建立子執行緒
    HANDLE h = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);//主執行緒結束後,子執行緒也隨之結束.
    Sleep(3000);//此處Sleep讓你能看到子執行緒列印I'm Sleeping

    //呼叫過WakeUp後,要Sleep一會,不然主執行緒就直接結束了.
    t.WakeUp();
    Sleep(2000);
    return 0;
}

//這種只是來演示,主執行緒為死迴圈時,和子執行緒交替執行的情形.
//不能實現
int main4()
{
    Test t;
    //建立子執行緒
    HANDLE h = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);//如果是死迴圈,那麼主執行緒不結束,子執行緒也不會結束.
    while (true)
    {
        Sleep(1000);
        cout << "主執行緒" << endl;
    }

    return 0;
}


//用兩個子執行緒實現,發現兩個子執行緒之間的生存期是相互獨立的.它們只受主執行緒的影響.
//可以實現.
int main5()
{
    Test t;
    HANDLE h[2];
    h[0] = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);
    Sleep(10);//如果不加這個Sleep,多數情況下會先列印Sleeping,然後列印awake,但是也有情況會直接列印awake.
    h[1] = CreateThread(NULL, 0, ThreadFun2, &t, 0, NULL);
    WaitForMultipleObjects(2, h, TRUE, INFINITE);
    return 0;
}

三.收穫

1.主執行緒結束後進程結束,子執行緒也終止了.

2.如果不設定主執行緒去等待子執行緒,兩者是交替執行的.比如main4.

3.兩個子執行緒之間的生存期是相互獨立的