實例解析C++/CLI線程之線程狀態持久性

其他形式的同步

  我們可使用類Monitor與類Thread中的某些函數,直接控制線程的同步,請看例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中,創建一個MessageBuffer類型的共享緩衝區;接着在標記2a、2b、2c中,創建了一個線程用於處理放置於緩衝區中的每條信息;標記3a、3b和3c,也創建了一個線程,並在共享緩衝區中放置了連續的5條信息以便處理。這兩個線程已被同步,因此處理者線程必須等到有"東西"放入到緩衝區中,纔可以進行處理,且在前一條信息被處理完之前,不能放入第二條信息。在標記4中,將一直等待,直到創建者線程完成它的工作。

  當標記5執行時,處理者線程必須處理所有創建者線程放入的信息,因爲使用了Thread::Interrupt讓其停止工作,並繼續等待標記6中調用的Thread::Join,這個函數允許調用線程阻塞它自己,直到其他線程結束。(一個線程可指定一個等待的最大時間,而不用無限等待下去。)

  線程CreateMessages非常清晰明瞭,它向共享緩衝區中寫入了5條信息,並在每條信息之間等待2秒。爲把一個線程掛起一個給定的時間(以毫秒計),我們調用了Thread::Sleep,在此,一個睡眠的線程可再繼續執行,原因在於運行時環境,而不是另一個線程。

  線程ProcessMessages甚至更加簡單,因爲它利用了類MessageBuffer來做它的所有工作。類MessageBuffer中的函數是被同步的,因此在同一時間,只有一個函數能訪問共享緩衝區。

  主程序首先啓動處理者線程,這個線程會執行ProcessMessages,其將獲得父對象的同步鎖;然而,它立即調用了標記10中的Wait函數,這個函數將讓它一直等待,直到再次被告之運行,期間,它也交出了同步鎖,這樣,允許創建者線程得到同步鎖並執行SetMessage。一旦函數把新的信息放入到共享緩衝區中,就會調用標記8中的Pulse,其允許等待同步鎖的任意線程被喚醒,並繼續執行下去。但是,在SetMessage執行完成之前,這些都不可能發生,因爲它在函數返回前都不可能交出同步鎖。如果情況一旦發生,處理者線程將重新得到同步鎖,並從標記10之後開始繼續執行。此處要說明的是,一個線程即可無限等待,也可等到一個指定的時間到達。插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

  請仔細留意,處理者線程啓動於創建者線程之前。如果以相反的順序啓動,將會在沒有處理者線程等待的情況下,添加第一條信息,此時,沒有可供喚醒處理者線程,當處理者線程運行到它的第一個函數調用Wait時,將會錯過第一條信息,且只會在第二條信息存儲時被喚醒。

共3頁。 1 2 3 8
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章