windows C++ 并行编程-异步消息块(四)
join 和 multitype_join 类
concurrency::join 和 concurrency::multitype_join 类允许你等待一组源中的每个成员接收消息。 join 类作用于具有通用消息类型的源对象。 multitype_join 类作用于可具有不同消息类型的源对象。
读取 join 或 multitype_join 对象类似于在将 bWaitAll 参数设置为 TRUE 的情况下调用 Windows API 函数 WaitForMultipleObjects。 但是,与 choice 对象一样,join 和 multitype_join 对象使用将数据绑定到事件本身而不是外部同步对象的事件机制。
读取 join 对象会生成 std::vector 对象。 读取 multitype_join 对象会生成 std::tuple 对象。 元素按照其相应源缓冲区链接到 join 或 multitype_join 对象的相同顺序出现在这些对象中。 由于将源缓冲区链接到 join 或 multitype_join 对象的顺序与生成的 vector 或 tuple 对象中的元素顺序相关联,因此我们建议不要从联接中取消链接现有的源缓冲区。 这样做可能会导致未指定的行为。
贪婪与非贪婪联接
join 和 multitype_join 类支持贪婪和非贪婪联接的概念。 当消息可用时,贪婪联接会接受其每个源中的消息,直到所有消息都可用。 非贪婪联接分两个阶段接收消息。 首先,非贪婪联接会一直等到从其每个源为其提供消息。 然后,在所有源消息都可用后,非贪婪联接会尝试保留其中的每条消息。 如果它可以保留每条消息,则会使用所有消息并将其传播到目标。 否则,它会释放或取消消息保留,并再次等待每个源接收消息。
贪婪联接比非贪婪联接的性能更好,因为它们立即接受消息。 但是,在极少数情况下,贪婪联接会导致死锁。 如果有多个联接包含一个或多个共享源对象,请使用非贪婪联接。
示例
以下示例使用基本结构来演示如何使用 join 类。 此示例使用 concurrency::make_join 函数创建一个从三个 single_assignment 对象接收消息的 join 对象。 此示例计算不同的斐波那契数,将每个结果存储在不同的 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::parallel_invoke 算法并行计算斐波那契数。
timer 类
concurrency::timer 类充当消息源。 timer 对象在指定的时间段过后向目标发送消息。 必须延迟发送消息或要按固定的间隔发送消息时,timer 类很有用。
timer 类将其消息仅发送到一个目标。 如果将构造函数中的 _PTarget 参数设置为 NULL,则稍后可以通过调用 concurrency::ISource::link_target 方法来指定目标。
timer 对象可以重复或不重复。 若要创建重复计时器,请在调用构造函数时为 _Repeating 参数传递 true。 否则,请为 _Repeating 参数传递 false 以创建非重复计时器。 如果计时器是重复的,则它会在每个间隔后向其目标发送相同的消息。
代理库创建处于未启动状态的 timer 对象。 若要启动 timer 对象,请调用 concurrency::timer::start 方法。 若要停止 timer 对象,请销毁该对象或调用 concurrency::timer::stop 方法。 若要暂停重复计时器,请调用 concurrency::timer::pause 方法。
示例
以下示例使用基本结构来演示如何使用 timer 类。 该示例使用 timer 和 call 对象来报告长时间运行的操作的进度。
// 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