共用方式為


非同步訊息區

代理程式程式庫會提供許多訊息區塊類型,可讓您以執行緒安全的方式在應用程式元件之間傳播訊息。這些訊息區經常用於具有不同的訊息傳遞常式,例如 concurrency::sendconcurrency::asendconcurrency::receive,以及 concurrency::try_receive。如需代理程式程式庫所定義之訊息傳遞常式的詳細資訊,請參閱訊息傳遞函式

章節

此主題包括下列章節:

  • 來源和目標

  • 訊息傳播

  • 訊息區類型的概觀

  • unbounded_buffer 類別

  • overwrite_buffer 類別

  • single_assignment 類別

  • call 類別

  • transformer 類別

  • choice 類別

  • join 和 multitype_join 類別

  • timer 類別

  • 訊息篩選

  • 訊息保留

來源和目標

來源和目標是訊息傳遞中的兩個重要參與者。「來源」(Source) 是指傳送訊息的通訊端點。「目標」(Target) 是指接收訊息的通訊端點。您可以將來源視為讀取的端點,而將目標視為寫入的端點。應用程式會將來源和目標連接在一起,以便構成「訊息網路」(Messaging Network)。

代理程式庫使用兩個抽象類別表示來源與目標: concurrency::ISourceconcurrency::ITarget。當做來源的訊息區類型會衍生自 ISource,而當做目標的訊息區類型則衍生自 ITarget。當做來源和目標的訊息區塊類型衍生自 ISourceITarget

Top

訊息傳播

「訊息傳播」(Message Propagation) 是將訊息從一個元件傳送至另一個元件的動作。當提供訊息給訊息區塊時,訊息區塊可以接受、拒絕或延後該訊息。每個訊息區塊類型以不同方式儲存及傳輸訊息。例如,unbounded_buffer 類別會儲存不限數目的訊息,overwrite_buffer 類別每次儲存一則訊息,而 transformer 類別則會儲存每則訊息的變更版本。本文件稍後將詳細說明這些訊息區塊類型。

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

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

應用程式會將來源和目標連接在一起,以便構成「訊息網路」(Messaging Network)。您通常會連結網路,並呼叫 sendasend 將資料傳遞至網路。若要連接到目標的來源訊息區塊,呼叫 concurrency::ISource::link_target 方法。若要中斷目標來源區塊,呼叫 concurrency::ISource::unlink_target 方法。若要中斷來源區塊與所有其目標,呼叫 concurrency::ISource::unlink_targets 方法。當其中一個預先定義的訊息範圍類型離開範圍或終結時,它會與任何目標區塊中斷連接。有些訊息區塊類型會限制訊息區塊可寫入的目標數目上限。下節將描述套用至預先定義之訊息區塊類型的限制。

Top

訊息區類型的概觀

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

  • unbounded_buffer
    儲存訊息的佇列。

  • overwrite_buffer
    儲存一則可多次寫入和讀取的訊息。

  • single_assignment
    儲存一則可寫入一次和讀取多次的訊息。

  • call
    當它收到訊息時執行工作。

  • transformer
    當它收到資料時執行工作,並將該項工作的結果傳送至另一個目標區塊。transformer 類別可以針對不同的輸入和輸出類型運作。

  • choice
    從一組來源中選取第一則可用的訊息。

  • join 和 multitype join
    等候從一組來源收到所有訊息,然後將這些訊息結合成另一個訊息區的一則訊息。

  • timer
    定期將訊息傳送至目標區塊。

這些訊息區類型具有不同的特性,讓它們可用於不同的情況。下面是其中某些特性:

  • 傳播類型 (Propagation Type):訊息區會當做資料的來源、資料的接收者,或兩者都是。

  • 訊息順序 (Message Ordering):訊息區是否維持傳送或接收訊息的原始順序。每個預先定義的訊息區類型都會維持它傳送或接收訊息的原始順序。

  • 來源計數 (Source Count):訊息區可讀取的來源數目上限。

  • 目標計數 (Target Count):訊息區可寫入的目標數目上限。

下表顯示這些特性與各種訊息區類型的關聯。

訊息區類型

傳播類型 (來源、目標或兩者都是)

訊息順序 (已排序或未排序)

來源計數

目標計數

unbounded_buffer

Both

已排序

無限制

無限制

overwrite_buffer

Both

已排序

無限制

無限制

single_assignment

Both

已排序

無限制

無限制

call

目標

已排序

無限制

不適用

transformer

Both

已排序

無限制

1

choice

Both

已排序

10

1

join

Both

已排序

無限制

1

multitype_join

Both

已排序

10

1

timer

來源

不適用

不適用

1

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

Top

unbounded_buffer 類別

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

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 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;
}

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

33
44
55

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

Top

overwrite_buffer 類別

Concurrency::overwrite_buffer 類別類似於unbounded_buffer類別,除了, overwrite_buffer物件可以儲存只是一封郵件。此外,當目標從 overwrite_buffer 物件收到訊息時,並不會從緩衝區中移除該訊息。因此,多個目標會接收此訊息的複本。

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

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 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;
}

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

55
55
55

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

Top

single_assignment 類別

Concurrency::single_assignment 類別類似於overwrite_buffer類別,除了, single_assignment物件可以被寫回只執行一次。與 overwrite_buffer 類別相同的是,當目標從 single_assignment 物件收到訊息時,並不會從該物件中移除該訊息。因此,多個目標會接收此訊息的複本。當您想要將一則訊息廣播至多個元件時,single_assignment 類別就很有用。

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 single_assignment 類別用法的基本結構。這個範例會將三個值傳送至 single_assignment 物件,然後從相同物件讀取目前值三次。這個範例與 overwrite_buffer 類別的範例類似。雖然 overwrite_buffersingle_assignment 類別都會儲存一則訊息,不過 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;
}

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

33
33
33

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

Top

call 類別

Concurrency::call 類別是訊息收件者收到資料時會執行的工作功能。這個工作函式可以是 Lambda 運算式、函式物件或函式指標。call 物件與一般函式呼叫的行為不同,因為它會以平行方式處理傳送訊息給它的其他元件。當 call 物件收到訊息時,如果它正在執行工作,就會將該訊息加入至佇列。每個 call 物件都會按照收到訊息的順序來處理佇列的訊息。

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 call 類別用法的基本結構。這個範例會建立可將收到的每個值列印至主控台的 call 物件。然後範例會將三個值傳送至 call 物件。因為 call 物件會在不同執行緒上處理訊息,所以這個範例也會使用計數器變數和 event 物件,以確保 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();
}

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

33
44
55

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

Top

transformer 類別

Concurrency::transformer 類別的作用是這兩個郵件收件者,而是郵件的寄件者。transformer 類別與 call 類別很相似,因為它會在收到資料時執行使用者定義的工作函式。不過,transformer 類別也會將工作函式的結果傳送至接收者物件。與 call 物件相同的是,transformer 物件會以平行方式處理傳送訊息給它的其他元件。當 transformer 物件收到訊息時,如果它正在執行工作,就會將該訊息加入至佇列。每個 transformer 物件都會按照收到訊息的順序來處理其佇列的訊息。

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

與代理程式程式庫所提供之所有其他非同步訊息區類型不同的是,transformer 類別可以針對不同的輸入和輸出類型運作。這種在不同類型之間轉換資料的能力讓 transformer 類別成為許多並行網路中的重要元件。此外,您可以在 transformer 物件的工作函式中加入更精細的平行功能。

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 transformer 類別用法的基本結構。這個範例會建立可將每個輸入 int 值乘以 0.33 的 transformer 物件,以便產生 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.89
14.52
18.15

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

Top

choice 類別

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

從 choice 物件中讀取類似於呼叫 Windows API WaitForMultipleObjects 函式 (當它將 bWaitAll 參數設定為 FALSE 時)。不過,choice 類別會將資料繫結至事件本身,而非外部同步處理物件。

一般來說,您可以使用choice類別一起 concurrency::receive 函式,來驅動應用程式中的控制流程。當您必須在具有不同類型的訊息緩衝區之間選取時,請使用 choice 類別。當您必須在具有相同類型的訊息緩衝區之間選取時,請使用 single_assignment 類別。

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

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 choice 類別用法的基本結構。這個範例會使用 concurrency::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;
   }
}

這個範例 (Example) 會產生下列範例 (Sample) 輸出:

fib35 received its value first. Result = 9227465

因為計算第 35 個 Fibonacci 數字的工作不保證最先完成,這個範例的結果可能有所不同。

這個範例會使用 concurrency::parallel_invoke 來計算費氏數平行演算法。如需 parallel_invoke 的詳細資訊,請參閱平行演算法

如需示範如何使用 choice 類別的完整範例,請參閱 HOW TO:在已完成的工作之中選取

Top

join 和 multitype_join 類別

Concurrency::joinconcurrency::multitype_join 類別可讓您聽到的一組來源的每個成員,來接收訊息。join 類別會針對具有相同訊息類型的來源物件運作。multitype_join 類別會針對可以具有不同訊息類型的來源物件運作。

joinmultitype_join 物件中讀取類似於呼叫 Windows API WaitForMultipleObjects 函式 (當它將 bWaitAll 參數設定為 TRUE 時)。不過,與 choice 物件相同的是,joinmultitype_join 物件所使用的事件機制會將資料繫結至事件本身,而非外部同步處理物件。

join 物件中讀取會產生 std::vector 物件。從 multitype_join 物件中讀取會產生 std::tuple 物件。項目出現在這些物件中的順序與其對應來源緩衝區連結至 joinmultitype_join 物件的順序相同。因為您將來源緩衝區連結至 joinmultitype_join 物件的順序是與結果 vectortuple 物件中的項目順序相關聯,建議您不要取消連結現有的來源緩衝區與 join。這樣做可能會造成未指定的行為。

Dd504833.collapse_all(zh-tw,VS.110).gif窮盡與非窮盡聯結

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

窮盡聯結的執行效能比非窮盡聯結要好,因為它們會立即接受訊息。不過在極罕見的情況下,窮盡聯結可能會導致死結。當您擁有多個包含一個或多個共用來源物件的聯結時,請使用非窮盡聯結。

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 join 類別用法的基本結構。這個範例會使用 concurrency::make_join 函式來建立join物件會接收的三single_assignment物件。這個範例會計算不同的 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 = 9227465
fib37 = 24157817
half_of_fib42 = 1.33957e+008

這個範例會使用 concurrency::parallel_invoke 來計算費氏數平行演算法。如需 parallel_invoke 的詳細資訊,請參閱平行演算法

如需示範如何使用 join 類別的完整範例,請參閱 HOW TO:在已完成的工作之中選取逐步解說:使用聯結以避免死結

Top

timer 類別

Concurrency::timer 類別的作用是做為訊息來源。timer 物件會在經過指定的時間期限之後,將訊息傳送至目標。當您必須延後傳送訊息,或者想要定期傳送訊息時,timer 類別就很有用。

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

timer 物件可以是重複或非重複的。若要建立重複的 timer,當您呼叫建構函式時,請將 true 傳遞給 _Repeating 參數。否則,請將 false 傳遞給 _Repeating 參數,以便建立非重複的 timer。如果 timer 是重複的,它就會在每個間隔之後,將相同的訊息傳送至其目標。

代理程式程式庫會建立處於非啟動狀態的 timer 物件。若要啟動計時器物件時,呼叫 concurrency::timer::start 方法。若要停止timer物件,終結物件或呼叫 concurrency::timer::stop 方法。若要暫停重複的計時器,呼叫 concurrency::timer::pause 方法。

Dd504833.collapse_all(zh-tw,VS.110).gif範例

下列範例顯示 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;
}

這個範例 (Example) 會產生下列範例 (Sample) 輸出:

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

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

Top

訊息篩選

當您建立訊息區塊物件時,可以提供「篩選函式」(Filter Function),決定訊息區塊會接受或拒絕訊息。篩選函式是確保訊息區塊只接收特定值的實用方法。

下列範例示範如何建立透過篩選函式只接受偶數的 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 (_Type)
bool (_Type const &)

若要排除不必要的資料複製,當您的彙總型別是以傳值方式傳播時,請使用第二個形式。

訊息篩選支援「資料流程」(Dataflow) 程式撰寫模型,其元件會在收到資料時執行計算。如需在訊息傳遞網路中使用篩選函式來控制資料流程的範例,請參閱 HOW TO:使用訊息區篩選條件逐步解說:建立資料流程代理程式逐步解說:建立影像處理網路

Top

訊息保留

「訊息保留」(Message Reservation) 可讓訊息區塊保留訊息以供稍後使用。訊息保留通常不是直接使用。不過,了解訊息保留有助於更加了解某些預先定義之訊息區塊類型的行為。

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

窮盡聯結也會從多個來源讀取輸入訊息,它會在等候從每個來源接收訊息的同時,使用訊息保留以讀取其他訊息。例如,請考慮可從訊息區塊 AB 接收訊息的窮盡聯結。如果此窮盡聯結從 B 接收兩則訊息,但尚未從 A 收到任何訊息,窮盡聯結會儲存來自 B 第二則訊息的唯一訊息識別碼。在窮盡聯結收到來自 A 的訊息並向外傳播這些訊息之後,它會使用儲存的訊息識別碼,判斷來自 B 的第二則訊息是否仍然可以使用。

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

Top

請參閱

概念

非同步代理程式程式庫