ransformer 类
concurrency::transformer 类既充当消息接收方,也充当消息发送方。 transformer 类与 call 类类似,因为它在接收数据时执行用户定义的工作函数。 但是,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
choice 类
concurrency::choice 类从一组源中选择第一条可用消息。 choice 类表示控制流机制而不是数据流机制(主题异步代理库介绍了数据流与控制流之间的差别)。
读取 choice 对象类似于在将 bWaitAll 参数设置为 FALSE 的情况下调用 Windows API 函数 WaitForMultipleObjects。 但是,choice 类会将数据绑定到事件本身而不是外部同步对象。
通常,你会将 choice 类与 concurrency::receive 函数一起使用来驱动应用程序中的控制流。 必须在具有不同类型的消息缓冲区中进行选择时,请使用 choice 类。 必须在具有相同类型的消息缓冲区中进行选择时,请使用 single_assignment 类。
将源链接到 choice 对象的顺序非常重要,因为这可以确定选择了哪条消息。 例如,假设你要将已包含一条消息的多个消息缓冲区链接到 choice 对象。 choice 对象将从它链接到的第一个源中选择该消息。 链接所有源后,choice 对象会保留每个源接收消息的顺序。
示例
以下示例使用基本结构来演示如何使用 choice 类。 此示例使用 concurrency::make_choice 函数创建一个 choice 对象,该对象在三个消息块中进行选择。 然后,该示例计算各种斐波那契数并将每个结果存储在不同的消息块中。 然后,该示例将基于首先完成的运算的消息输出到控制台。
// 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 个斐波那契数的任务首先完成,因此此示例的输出可能有所不同。此示例使用 concurrency::parallel_invoke 算法并行计算斐波那契数。