實例解析C++/CLI線程之線程狀態(tài)持久性

字號:

其他形式的同步
    我們可使用類Monitor與類Thread中的某些函數(shù),直接控制線程的同步,請看例1。
    例1:
    using namespace System;
    using namespace System::Threading;
    int main()
    {
    /*1*/ MessageBuffer^ m = gcnew MessageBuffer;
    /*2a*/ ProcessMessages^ pm = gcnew ProcessMessages(m);
    /*2b*/ Thread^ pmt = gcnew Thread(gcnew ThreadStart(pm,&ProcessMessages::ProcessMessagesEntryPoint));
    /*2c*/ pmt->Start();
    /*3a*/ CreateMessages^ cm = gcnew CreateMessages(m);
    /*3b*/ Thread^ cmt = gcnew Thread(gcnew ThreadStart(cm, &CreateMessages::CreateMessagesEntryPoint));
    /*3c*/ cmt->Start();
    /*4*/ cmt->Join();
    /*5*/ pmt->Interrupt();
    /*6*/ pmt->Join();
    Console::WriteLine("Primary thread terminating");
    }
    public ref class MessageBuffer
    {
    String^ messageText;
    public:
    void SetMessage(String^ s)
    {
    /*7*/ Monitor::Enter(this);
    messageText = s;
    /*8*/ Monitor::Pulse(this);
    Console::WriteLine("Set new message {0}", messageText);
    Monitor::Exit(this);
    }
    void ProcessMessages()
    {
    /*9*/ Monitor::Enter(this);
    while (true)
    {
     try
     {
    /*10*/ Monitor::Wait(this);
     }
     catch (ThreadInterruptedException^ e)
     {
    Console::WriteLine("ProcessMessage interrupted");
    return;
     }
     Console::WriteLine("Processed new message {0}", messageText);
    }
    Monitor::Exit(this);
    }
    };
    public ref class CreateMessages
    {
    MessageBuffer^ msg;
    public:
    CreateMessages(MessageBuffer^ m)
    {
    msg = m;
    }
    void CreateMessagesEntryPoint()
    {
    for (int i = 1; i <= 5; ++i)
    {
     msg->SetMessage(String::Concat("M-", i.ToString()));
     Thread::Sleep(2000);
    }
    Console::WriteLine("CreateMessages thread terminating");
    }
    };
    public ref class ProcessMessages
    {
    MessageBuffer^ msg;
    public:
    ProcessMessages(MessageBuffer^ m)
    {
    msg = m;
    }
    void ProcessMessagesEntryPoint()
    {
    msg->ProcessMessages();
    Console::WriteLine("ProcessMessages thread terminating");
    }
    };
    在標記1中,創(chuàng)建一個MessageBuffer類型的共享緩沖區(qū);接著在標記2a、2b、2c中,創(chuàng)建了一個線程用于處理放置于緩沖區(qū)中的每條信息;標記3a、3b和3c,也創(chuàng)建了一個線程,并在共享緩沖區(qū)中放置了連續(xù)的5條信息以便處理。這兩個線程已被同步,因此處理者線程必須等到有"東西"放入到緩沖區(qū)中,才可以進行處理,且在前一條信息被處理完之前,不能放入第二條信息。在標記4中,將一直等待,直到創(chuàng)建者線程完成它的工作。
    當標記5執(zhí)行時,處理者線程必須處理所有創(chuàng)建者線程放入的信息,因為使用了Thread::Interrupt讓其停止工作,并繼續(xù)等待標記6中調用的Thread::Join,這個函數(shù)允許調用線程阻塞它自己,直到其他線程結束。(一個線程可指定一個等待的時間,而不用無限等待下去。)
    線程CreateMessages非常清晰明了,它向共享緩沖區(qū)中寫入了5條信息,并在每條信息之間等待2秒。為把一個線程掛起一個給定的時間(以毫秒計),我們調用了Thread::Sleep,在此,一個睡眠的線程可再繼續(xù)執(zhí)行,原因在于運行時環(huán)境,而不是另一個線程。
    線程ProcessMessages甚至更加簡單,因為它利用了類MessageBuffer來做它的所有工作。類MessageBuffer中的函數(shù)是被同步的,因此在同一時間,只有一個函數(shù)能訪問共享緩沖區(qū)。
    主程序首先啟動處理者線程,這個線程會執(zhí)行ProcessMessages,其將獲得父對象的同步鎖;然而,它立即調用了標記10中的Wait函數(shù),這個函數(shù)將讓它一直等待,直到再次被告之運行,期間,它也交出了同步鎖,這樣,允許創(chuàng)建者線程得到同步鎖并執(zhí)行SetMessage。一旦函數(shù)把新的信息放入到共享緩沖區(qū)中,就會調用標記8中的Pulse,其允許等待同步鎖的任意線程被喚醒,并繼續(xù)執(zhí)行下去。但是,在SetMessage執(zhí)行完成之前,這些都不可能發(fā)生,因為它在函數(shù)返回前都不可能交出同步鎖。如果情況一旦發(fā)生,處理者線程將重新得到同步鎖,并從標記10之后開始繼續(xù)執(zhí)行。此處要說明的是,一個線程即可無限等待,也可等到一個指定的時間到達。插1是程序的輸出。
    插1:
    Set new message M-1
    Processed new message M-1
    Set new message M-2
    Processed new message M-2
    Set new message M-3
    Processed new message M-3
    Set new message M-4
    Processed new message M-4
    Set new message M-5
    Processed new message M-5
    CreateMessages thread terminating
    ProcessMessage interrupted
    ProcessMessages thread terminating
    Primary thread terminating
    請仔細留意,處理者線程啟動于創(chuàng)建者線程之前。如果以相反的順序啟動,將會在沒有處理者線程等待的情況下,添加第一條信息,此時,沒有可供喚醒處理者線程,當處理者線程運行到它的第一個函數(shù)調用Wait時,將會錯過第一條信息,且只會在第二條信息存儲時被喚醒。