Share via


非同步訊息區

Agents Library 提供數種訊息區塊類型,可讓您以安全線程的方式在應用程式元件之間傳播訊息。 這些訊息區塊類型通常與各種訊息傳遞常式搭配使用,例如 concurrency::send 、concurrency::asend concurrency::receive 和 concurrency::try_receive 。 如需代理程式程式庫所定義之訊息傳遞常式的詳細資訊,請參閱 訊息傳遞函式

區段

本主題包含下列幾節:

來源和目標

來源和目標是訊息傳遞中的兩個重要參與者。 來源 是指傳送訊息的通訊端點。 目標 是指接收訊息的通訊端點。 您可以將來源視為您讀取的端點,並將目標視為您寫入的端點。 應用程式會將來源和目標連線在一起,以形成 傳訊網路

Agents Library 使用兩個抽象類別別來代表來源和目標: concurrency::ISource concurrency::ITarget 。 做為來源的訊息區塊類型衍生自 ISource ;做為目標的訊息區塊類型衍生自 ITarget 。 做為來源和目標的訊息區塊類型同時衍生自 ISourceITarget

[靠上]

訊息傳播

訊息傳播 是將訊息從某個元件傳送到另一個元件的行為。 當訊息區塊提供訊息時,它可以接受、拒絕或延後該訊息。 每個消息塊類型都會以不同的方式儲存和傳輸訊息。 例如,類別 unbounded_buffer 會儲存不限數量的訊息、 overwrite_buffer 類別一次儲存單一訊息,而轉換器類別會儲存每個訊息的改變版本。 本檔稍後會更詳細地說明這些訊息區塊類型。

當訊息區塊接受訊息時,它可以選擇性地執行工作,如果消息塊是來源,請將產生的訊息傳遞至網路的另一個成員。 消息塊可以使用篩選函式來拒絕不想要接收的訊息。 本主題稍後會在訊息篩選一節 中詳細說明篩選 條件。 延後訊息的訊息區塊可以保留該訊息,並在稍後取用該訊息。 在本主題稍後的訊息保留區一節 中,會更詳細地說明訊息保留

Agents 程式庫可讓訊息區塊以非同步或同步方式傳遞訊息。 例如,當您同步將訊息傳遞至訊息區塊時, send 執行時間會封鎖目前的內容,直到目標區塊接受或拒絕訊息為止。 例如,當您以 asend 非同步方式將訊息傳遞至訊息區塊時,執行時間會將訊息提供給目標,如果目標接受訊息,執行時間會排程將訊息傳播至接收者的非同步工作。 執行時間會使用輕量型工作,以合作方式傳播訊息。 如需輕量型工作的詳細資訊,請參閱 工作排程器

應用程式會將來源和目標連線在一起,以形成傳訊網路。 一般而言,您會連結網路並呼叫 sendasend 將資料傳遞至網路。 若要將來源訊息區塊連線至目標,請呼叫 concurrency::ISource::link_target 方法。 若要中斷來源區塊與目標的連接,請呼叫 concurrency::ISource::unlink_target 方法。 若要中斷來源區塊與其所有目標的連接,請呼叫 concurrency::ISource::unlink_targets 方法。 當其中一個預先定義的訊息區塊類型離開範圍或終結時,它會自動中斷與任何目標區塊的連線。 某些訊息區塊類型會限制可以寫入的目標數目上限。 下一節說明套用至預先定義訊息區塊類型的限制。

[靠上]

消息塊類型概觀

下表簡短描述重要訊息區塊類型的角色。

unbounded_buffer
儲存訊息佇列。

overwrite_buffer
儲存一則訊息,這些訊息可以寫入和讀取多次。

single_assignment
儲存一則訊息,可寫入一次並從多次讀取。

call
在收到訊息時執行工作。

變壓器
在接收資料並將該工作的結果傳送至另一個目標區塊時,執行工作。 類別 transformer 可以處理不同的輸入和輸出類型。

choice
從一組來源選取第一個可用的訊息。

聯結和多重類型聯結
等候所有訊息從一組來源接收,然後將訊息合併成另一個訊息區塊的訊息。

計時 器
定期將訊息傳送至目標區塊。

這些訊息區塊類型具有不同的特性,使其適用于不同的情況。 以下是一些特性:

  • 傳播類型 :訊息區塊是否做為資料來源、資料接收者或兩者。

  • 訊息順序 :訊息區塊是否維護傳送或接收訊息的原始順序。 每個預先定義的訊息區塊類型都會維護其傳送或接收訊息的原始順序。

  • 來源計數 :訊息區塊可以讀取的來源數目上限。

  • 目標計數 :訊息區塊可以寫入的目標數目上限。

下表顯示這些特性如何與各種訊息區塊類型產生關聯。

消息塊類型 傳播類型 (來源、目標或兩者) 訊息排序(已排序或未排序) 來源計數 目標計數
unbounded_buffer 兩者 排序 無界限 無界限
overwrite_buffer 兩者 排序 無界限 無界限
single_assignment 兩者 排序 無界限 無界限
call 目標 排序 無界限 不適用
transformer 兩者 排序 無界限 1
choice 兩者 排序 10 1
join 兩者 排序 無界限 1
multitype_join 兩者 排序 10 1
timer Source 不適用 不適用 1

下列各節將更詳細地描述訊息區塊類型。

[靠上]

unbounded_buffer 類別

concurrency ::unbounded_buffer 類別代表一般用途非同步傳訊結構。 這個類別會儲存可由多個來源寫入或由多個目標讀取之訊息的先進先出 (FIFO) 佇列。 當目標從 unbounded_buffer 物件接收訊息時,該訊息會從訊息佇列中移除。 因此,雖然 unbounded_buffer 物件可以有多個目標,但只有一個目標會收到每個訊息。 當您想要將多則訊息傳遞給其他元件,而且該元件必須接收每則訊息時,unbounded_buffer 類別就很有用。

範例

下列範例示範如何使用 unbounded_buffer 類別的基本結構。 這個範例會將三個 unbounded_buffer 值傳送至 物件,然後從相同的 物件讀取這些值。

// unbounded_buffer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an unbounded_buffer object that works with
   // int data.
   unbounded_buffer<int> items;

   // Send a few items to the unbounded_buffer object.
   send(items, 33);
   send(items, 44);
   send(items, 55);

   // Read the items from the unbounded_buffer object and print
   // them to the console.
   wcout << receive(items) << endl;
   wcout << receive(items) << endl;
   wcout << receive(items) << endl;
}

這個範例會產生下列輸出:

334455

如需示範如何使用 unbounded_buffer 類別的完整範例,請參閱 如何:實作各種生產者-取用者 模式。

[靠上]

overwrite_buffer 類別

concurrency::overwrite_buffer 類別與 類別類似 unbounded_buffer ,不同之處在于 overwrite_buffer 物件只儲存一則訊息。 此外,當目標從 overwrite_buffer 物件接收訊息時,該訊息不會從緩衝區中移除。 因此,多個目標會接收此訊息的複本。

當您想要將多個訊息傳遞至另一個元件,但該元件只需要最新的值時,類別 overwrite_buffer 就很有用。 當您想要將訊息廣播至多個元件時,這個類別也很有用。

範例

下列範例示範如何使用 overwrite_buffer 類別的基本結構。 這個範例會將三個 overwrite _buffer 值傳送至 物件,然後從相同的物件讀取目前值三次。 這個範例類似于 類別的 unbounded_buffer 範例。 不過,類別 overwrite_buffer 只會儲存一則訊息。 此外,執行時間不會在讀取訊息之後從 overwrite_buffer 物件中移除訊息。

// overwrite_buffer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an overwrite_buffer object that works with
   // int data.
   overwrite_buffer<int> item;

   // Send a few items to the overwrite_buffer object.
   send(item, 33);
   send(item, 44);
   send(item, 55);

   // Read the current item from the overwrite_buffer object and print
   // it to the console three times.
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
}

這個範例會產生下列輸出:

555555

如需示範如何使用 overwrite_buffer 類別的完整範例,請參閱 如何:實作各種生產者-取用者 模式。

[靠上]

single_assignment 類別

concurrency ::single_assignment 類別與 類別類似 overwrite_buffer ,不同之處在于 single_assignment 物件只能寫入一次。 與 overwrite_buffer 類別相同的是,當目標從 single_assignment 物件收到訊息時,並不會從此物件中移除該訊息。 因此,多個目標會接收此訊息的複本。 當您想要將一則訊息廣播至多個元件時,類別 single_assignment 會很有用。

範例

下列範例示範如何使用 single_assignment 類別的基本結構。 這個範例會將三個 single_assignment 值傳送至 物件,然後從相同的物件讀取目前值三次。 這個範例類似于 類別的 overwrite_buffer 範例。 雖然 和 single_assignment 類別都會 overwrite_buffer 儲存單一訊息, single_assignment 但類別只能寫入一次。

// single_assignment-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an single_assignment object that works with
   // int data.
   single_assignment<int> item;

   // Send a few items to the single_assignment object.
   send(item, 33);
   send(item, 44);
   send(item, 55);

   // Read the current item from the single_assignment object and print
   // it to the console three times.
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
}

這個範例會產生下列輸出:

333333

如需示範如何使用 single_assignment 類別的完整範例,請參閱 逐步解說:實作未來

[靠上]

call 類別

concurrency ::call 類別可作為接收資料時執行工作函式的訊息接收者。 此工作函式可以是 Lambda 運算式、函式物件或函式指標。 call物件的行為與一般函式呼叫不同,因為它會與傳送訊息的其他元件平行運作。 call如果物件在收到訊息時正在執行工作,則會將該訊息新增至佇列。 每個 call 物件都會依接收訊息的連續處理佇列訊息。

範例

下列範例示範如何使用 call 類別的基本結構。 此範例會 call 建立 物件,以將它接收的每個值列印到主控台。 然後,此範例會將三個值傳送至 call 物件。 因為物件會 call 處理個別執行緒上的訊息,因此此範例也會使用計數器變數和 事件 物件來確保 call 物件會在 wmain 函式傳回之前處理所有訊息。

// call-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // An event that is set when the call object receives all values.
   event received_all;

   // Counts the 
   long receive_count = 0L;
   long max_receive_count = 3L;

   // Create an call object that works with int data.
   call<int> target([&received_all,&receive_count,max_receive_count](int n) {
      // Print the value that the call object receives to the console.
      wcout << n << endl;
      
      // Set the event when all messages have been processed.
      if (++receive_count == max_receive_count)
         received_all.set();
   });

   // Send a few items to the call object.
   send(target, 33);
   send(target, 44);
   send(target, 55);

   // Wait for the call object to process all items.
   received_all.wait();
}

這個範例會產生下列輸出:

334455

如需示範如何使用 call 類別的完整範例,請參閱 如何:提供工作函式給呼叫和轉換器類別

[靠上]

transformer 類別

concurrency ::transformer 類別會同時做為訊息接收者和訊息傳送者。 類別類似于 類別 transformercall 因為它會在接收資料時執行使用者定義的工作函式。 不過,類別 transformer 也會將工作函式的結果傳送給接收者物件。 call如同 物件, transformer 物件會與傳送訊息的其他元件平行處理。 transformer如果物件在收到訊息時正在執行工作,則會將該訊息新增至佇列。 每個 transformer 物件都會依接收佇列訊息的順序來處理其佇列訊息。

類別 transformer 會將其訊息傳送至一個目標。 如果您將 _PTarget 建構函式中的 參數設定為 NULL ,您可以稍後呼叫 concurrency::link_target 方法來指定目標。

不同于代理程式程式庫所提供的所有其他非同步訊息區塊類型,類別 transformer 可以處理不同的輸入和輸出類型。 這項將資料從某個類型轉換成另一種類型的能力,使 transformer 類別成為許多並行網路中的關鍵元件。 此外,您可以在 物件的工作函式中新增更精細的 transformer 平行功能。

範例

下列範例示範如何使用 transformer 類別的基本結構。 這個範例會 transformer 建立 物件,以將每個輸入 int 值乘以 0.33,以產生 double 值做為輸出。 然後,此範例會從相同的 transformer 物件接收轉換的值,並將其列印至主控台。

// transformer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an transformer object that receives int data and 
   // sends double data.
   transformer<int, double> third([](int n) {
      // Return one-third of the input value.
      return n * 0.33;
   });

   // Send a few items to the transformer object.
   send(third, 33);
   send(third, 44);
   send(third, 55);

   // Read the processed items from the transformer object and print
   // them to the console.
   wcout << receive(third) << endl;
   wcout << receive(third) << endl;
   wcout << receive(third) << endl;
}

這個範例會產生下列輸出:

10.8914.5218.15

如需示範如何使用 transformer 類別的完整範例,請參閱 如何:在資料管線 中使用轉換器。

[靠上]

choice 類別

concurrency ::choice 類別會從一組來源選取第一個可用的訊息。 類別 choice 代表控制流程機制,而不是資料流程機制(非同步代理程式程式庫 主題 描述資料流程與控制流程之間的差異)。

從選擇物件讀取類似于在將 bWaitAll 參數設定為 FALSE 時呼叫 Windows API 函 WaitForMultipleObjects 式。 不過,類別會將 choice 資料系結至事件本身,而不是系結至外部同步處理物件。

一般而言,您會將 choice 類別與並行::receive 函式一 起使用,在應用程式中驅動控制流程。 當您必須選取具有不同類型的訊息緩衝區時,請使用 類別 choice 。 當您必須選取具有相同類型的訊息緩衝區時,請使用 類別 single_assignment

將來源連結至 choice 物件的順序很重要,因為它可以判斷選取的訊息。 例如,假設您已將包含訊息的多個訊息緩衝區連結至 choice 物件。 物件 choice 會從所連結的第一個來源選取訊息。 連結所有來源之後, choice 物件會保留每個來源接收訊息的順序。

範例

下列範例示範如何使用 choice 類別的基本結構。 此範例會使用 並行::make_choice 函式來建立在三個 choice 消息塊之間選取的物件。 然後,此範例會計算各種 Fibonacci 數位,並將每個結果儲存在不同的消息塊中。 然後,此範例會列印至主控台,訊息會以第一次完成的作業為基礎。

// choice-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Although the following thee message blocks are written to one time only, 
   // this example illustrates the fact that the choice class works with 
   // different message block types.

   // Holds the 35th Fibonacci number.
   single_assignment<int> fib35;
   // Holds the 37th Fibonacci number.
   overwrite_buffer<int> fib37;
   // Holds half of the 42nd Fibonacci number.
   unbounded_buffer<double> half_of_fib42;   

   // Create a choice object that selects the first single_assignment 
   // object that receives a value.
   auto select_one = make_choice(&fib35, &fib37, &half_of_fib42);

   // Execute a few lengthy operations in parallel. Each operation sends its 
   // result to one of the single_assignment objects.
   parallel_invoke(
      [&fib35] { send(fib35, fibonacci(35)); },
      [&fib37] { send(fib37, fibonacci(37)); },
      [&half_of_fib42] { send(half_of_fib42, fibonacci(42) * 0.5); }
   );

   // Print a message that is based on the operation that finished first.
   switch (receive(select_one))
   {
   case 0:
      wcout << L"fib35 received its value first. Result = " 
            << receive(fib35) << endl;
      break;
   case 1:
      wcout << L"fib37 received its value first. Result = " 
            << receive(fib37) << endl;
      break;
   case 2:
      wcout << L"half_of_fib42 received its value first. Result = " 
            << receive(half_of_fib42) << endl;
      break;
   default:
      wcout << L"Unexpected." << endl;
      break;
   }
}

此範例會產生下列範例輸出:

fib35 received its value first. Result = 9227465

由於計算第 35 Fibonacci 數位的工作不保證會先完成,因此此範例的輸出可能會有所不同。

此範例會使用 concurrency::p arallel_invoke 演算法平行計算 Fibonacci 數位。 如需 的詳細資訊 parallel_invoke ,請參閱 平行演算法

如需示範如何使用 choice 類別的完整範例,請參閱 How to: Select Among Completed Tasks

[靠上]

聯結和multitype_join類別

concurrency ::join concurrency::multitype_join 類別可讓您等候一組來源的每個成員接收訊息。 類別 join 會作用於具有通用訊息類型的來源物件。 類別 multitype_join 會針對可以具有不同訊息類型的來源物件執行動作。

joinmultitype_join 物件讀取,類似于在將 bWaitAll 參數設定為 TRUE 時呼叫 Windows API 函 WaitForMultipleObjects 式。 不過,就像物件一樣 choicejoin 物件會 multitype_join 使用事件機制,將資料系結至事件本身,而不是外部同步處理物件。

join 物件讀取會產生 std:: vector 物件。 從 multitype_join 物件讀取會產生 std:: tuple 物件。 元素會以與其對應來源緩衝區連結至 joinmultitype_join 物件的順序出現在這些物件中。 由於您將來源緩衝區連結至 joinmultitype_join 物件的順序與產生的 vectortuple 物件中的專案順序相關聯,因此建議您不要將現有的來源緩衝區從聯結中取消連結。 這樣做可能會導致未指定的行為。

貪婪與非貪婪聯結

joinmultitype_join 類別支援貪婪和非貪婪聯結的概念。 貪婪聯結 會接受來自其每個來源的訊息,因為訊息會變成可用,直到所有訊息都可用為止。 非窮盡聯結 會以兩個階段接收訊息。 首先,非貪婪的聯結會等候,直到其每個來源提供訊息為止。 其次,在所有來源訊息可供使用之後,非貪婪聯結會嘗試保留這些訊息的每一個。 如果它可以保留每個訊息,則會取用所有訊息,並將其傳播至其目標。 否則,它會釋放或取消訊息保留,並再次等候每個來源接收訊息。

貪婪聯結的執行效能優於非貪婪聯結,因為它們會立即接受訊息。 然而,在罕見的情況下,貪婪的聯結可能會導致死結。 當您有多個包含一或多個共用來源物件的聯結時,請使用非窮盡聯結。

範例

下列範例示範如何使用 join 類別的基本結構。 此範例會使用 concurrency::make_join 函式來建立從三 single_assignmentjoin 物件接收的物件。 此範例會計算各種 Fibonacci 數位、將每個結果儲存在不同的 single_assignment 物件中,然後列印至主控台,每個物件保留的結果 join 。 這個範例與 類別的 choice 範例類似,不同之處在于 join 類別會等候所有來源消息區塊接收訊息。

// join-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Holds the 35th Fibonacci number.
   single_assignment<int> fib35;
   // Holds the 37th Fibonacci number.
   single_assignment<int> fib37;
   // Holds half of the 42nd Fibonacci number.
   single_assignment<double> half_of_fib42;   

   // Create a join object that selects the values from each of the
   // single_assignment objects.
   auto join_all = make_join(&fib35, &fib37, &half_of_fib42);

   // Execute a few lengthy operations in parallel. Each operation sends its 
   // result to one of the single_assignment objects.
   parallel_invoke(
      [&fib35] { send(fib35, fibonacci(35)); },
      [&fib37] { send(fib37, fibonacci(37)); },
      [&half_of_fib42] { send(half_of_fib42, fibonacci(42) * 0.5); }
   );

   auto result = receive(join_all);
   wcout << L"fib35 = " << get<0>(result) << endl;
   wcout << L"fib37 = " << get<1>(result) << endl;
   wcout << L"half_of_fib42 = " << get<2>(result) << endl;
}

這個範例會產生下列輸出:

fib35 = 9227465fib37 = 24157817half_of_fib42 = 1.33957e+008

此範例會使用 concurrency::p arallel_invoke 演算法平行計算 Fibonacci 數位。 如需 的詳細資訊 parallel_invoke ,請參閱 平行演算法

如需示範如何使用 join 類別的完整範例,請參閱 如何:在已完成的工作 中選取和 逐步解說:使用聯結來防止死結

[靠上]

timer 類別

concurrency:: timer 類別 可作為訊息來源。 timer物件會在經過指定的一段時間之後,將訊息傳送至目標。 當您必須延遲傳送訊息或想要定期傳送訊息時,類別 timer 會很有用。

類別 timer 只會將其訊息傳送至一個目標。 如果您將 _PTarget 建構函式中的 參數設定為 NULL ,您稍後可以呼叫 concurrency::ISource::link_target 方法來指定目標。

timer物件可以重複或非重複。 若要建立重複計時器,請在呼叫建構函式時傳遞 true_Repeating 參數。 否則,傳遞 false_Repeating 參數以建立非重複計時器。 如果計時器重複,它會在每個間隔之後,將相同的訊息傳送至其目標。

Agents Library 會 timer 建立處於非啟動狀態的物件。 若要啟動計時器物件,請呼叫 concurrency::timer::start 方法。 若要停止 timer 物件,請終結 物件或呼叫 concurrency::timer::stop 方法。 若要暫停重複計時器,請呼叫 concurrency::timer::p ause 方法。

範例

下列範例示範如何使用 timer 類別的基本結構。 此範例會使用 timercall 物件來報告冗長的作業進度。

// timer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Create a call object that prints characters that it receives 
   // to the console.
   call<wchar_t> print_character([](wchar_t c) {
      wcout << c;
   });

   // Create a timer object that sends the period (.) character to 
   // the call object every 100 milliseconds.
   timer<wchar_t> progress_timer(100u, L'.', &print_character, true);

   // Start the timer.
   wcout << L"Computing fib(42)";
   progress_timer.start();

   // Compute the 42nd Fibonacci number.
   int fib42 = fibonacci(42);

   // Stop the timer and print the result.
   progress_timer.stop();
   wcout << endl << L"result is " << fib42 << endl;
}

此範例會產生下列範例輸出:

Computing fib(42)..................................................result is 267914296

如需示範如何使用 timer 類別的完整範例,請參閱 如何:定期 傳送訊息。

[靠上]

訊息篩選

當您建立消息塊物件時,您可以提供 篩選函 式來判斷消息塊是否接受或拒絕訊息。 篩選函式是保證訊息區塊只接收特定值的實用方式。

下列範例示範如何建立 unbounded_buffer 物件,該物件會使用篩選函式只接受偶數。 物件 unbounded_buffer 會拒絕奇數,因此不會將奇數傳播到其目標區塊。

// filter-function.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an unbounded_buffer object that uses a filter
   // function to accept only even numbers.
   unbounded_buffer<int> accept_evens(
      [](int n) {
         return (n%2) == 0;
      });

   // Send a few values to the unbounded_buffer object.
   unsigned int accept_count = 0;
   for (int i = 0; i < 10; ++i)
   {
      // The asend function returns true only if the target
      // accepts the message. This enables us to determine
      // how many elements are stored in the unbounded_buffer
      // object.
      if (asend(accept_evens, i))
      {
         ++accept_count;
      }
   }

   // Print to the console each value that is stored in the 
   // unbounded_buffer object. The unbounded_buffer object should
   // contain only even numbers.
   while (accept_count > 0)
   {
      wcout << receive(accept_evens) << L' ';
      --accept_count;
   }
}

這個範例會產生下列輸出:

0 2 4 6 8

篩選函式可以是 Lambda 函式、函式指標或函式物件。 每個篩選函式都會採用下列其中一種形式。

bool (T)
bool (T const &)

若要消除不必要的資料複製,當您擁有依值傳播的匯總類型時,請使用第二個表單。

訊息篩選支援 資料流程 程式設計模型,其中元件會在接收資料時執行計算。 如需使用篩選函式來控制訊息傳遞網路中資料流程的範例,請參閱 如何:使用消息塊篩選 逐步解說:建立資料流程代理程式和 逐步解說:建立映射處理網路

[靠上]

訊息保留

訊息保留 可讓訊息區塊保留訊息以供稍後使用。 通常不會直接使用訊息保留。 不過,瞭解訊息保留可協助您進一步瞭解某些預先定義訊息區塊類型的行為。

考慮非貪婪和貪婪聯結。 這兩者都使用訊息保留來保留訊息以供稍後使用。 稍早所述的 ,非貪婪聯結會以兩個階段接收訊息。 在第一個階段中,非貪婪 join 物件會等候其每個來源接收訊息。 然後,非貪婪的聯結會嘗試保留每一則訊息。 如果它可以保留每個訊息,則會取用所有訊息,並將其傳播至其目標。 否則,它會釋放或取消訊息保留,並再次等候每個來源接收訊息。

貪婪聯結也會從許多來源讀取輸入訊息,它會使用訊息保留來讀取其他訊息,同時等候接收來自每個來源的訊息。 例如,請考慮從消息區塊 AB 接收訊息的貪婪聯結。 如果貪婪聯結從 B 接收兩則訊息,但尚未收到 來自 的訊息 A ,則貪婪聯結會儲存來自 的第二個訊息的唯一訊息 B 識別碼。 當貪婪聯結從 接收訊息 A 並傳播這些訊息之後,它會使用儲存的訊息識別碼來查看來自 的第二個訊息 B 是否仍然可用。

當您實作自己的自訂消息塊類型時,可以使用訊息保留。 如需如何建立自訂消息塊類型的範例,請參閱 逐步解說:建立自訂消息塊

[靠上]

另請參閱

非同步代理程式程式庫