windows C++ 并行编程-异步消息块(一)
代理库提供了多种消息块类型,使你能够以线程安全的方式在应用程序组件之间传播消息。 这些消息块类型通常与 concurrency::send、concurrency::asend、concurrency::receive 和 concurrency::try_receive 等各种消息传递例程配合使用。
本文包含以下各节:
- 源和目标
- 消息传播
- 消息块类型概述
- unbounded_buffer 类
- overwrite_buffer 类
- single_assignment 类
- call 类
- transformer 类
- choice 类
- join 和 multitype_join 类
- timer 类
- 消息筛选
- 消息保留
由于较长,将分四部分讲解完毕。
源和目标
源和目标是消息传递的两个重要参与方。 源是指发送消息的通信终结点。 目标是指接收消息的通信终结点。 可将源视为从中读取的终结点,将目标视为要写入到的终结点。 应用程序将源和目标连接在一起以形成消息传递网络。
代理库使用两个抽象类来表示源和目标:concurrency::ISource 和 concurrency::ITarget。 充当源的消息块类型派生自 ISource;充当目标的消息块类型派生自 ITarget。 充当源和目标的消息块类型派生自 ISource 和 ITarget。
消息传播
消息传播是将消息从一个组件发送到另一个组件的行为。 向消息块提供某个消息时,消息块可以接受、拒绝或推迟该消息。 每种消息块类型以不同的方式存储和传输消息。 例如,unbounded_buffer 类存储无限数量的消息,overwrite_buffer 类一次存储一条消息,而 transformer 类存储每条消息的已更改版本。
当消息块接受消息时,它可以选择性地执行工作,如果该消息块是源,则会将生成的消息传递给网络的另一个成员。 消息块可以使用筛选器函数来拒绝它不想要接收的消息。 本主题稍后的消息筛选部分将更详细地介绍筛选器。 推迟消息的消息块可以保留该消息并在以后再使用它。
代理库允许消息块以异步或同步方式传递消息。 当你以同步方式(例如,使用 send 函数)将某个消息传递到消息块时,运行时会阻止当前上下文,直到目标块接受或拒绝该消息。 当你以异步方式(例如,使用 asend 函数)将某个消息传递到消息块时,运行时会将该消息提供给目标,如果目标接受消息,则运行时将计划一个异步任务,用于将该消息传播到接收方。 运行时使用轻量级任务以协作方式传播消息。 有关轻量级任务的详细信息,请参阅任务计划程序。
应用程序将源和目标连接在一起以形成消息传递网络。 通常,你会链接网络并调用 send 或 asend 以将数据传递到网络。 若要将源消息块连接到目标,请调用 concurrency::ISource::link_target 方法。 若要断开源块与目标的连接,请调用 concurrency::ISource::unlink_target 方法。 若要断开源块与其所有目标的连接,请调用 concurrency::ISource::unlink_targets 方法。 当某种预定义的消息块类型超出范围或被销毁时,它会自动断开与任何目标块的连接。 某些消息块类型会限制它们可以写入到的最大目标数。
消息块类型概述
下面简要描述了重要消息块类型的作用。
unbounded_buffer: 存储消息队列;
overwrite_buffer:存储一条可以多次写入并从中读取的消息;
single_assignment:存储一条可以一次写入并从中多次读取的消息;
call:收到消息时执行工作;
transformer:收到数据时执行工作,并将该工作的结果发送到另一个目标块。 transformer 类可以作用于不同的输入和输出类型;
choice:从一组源中选择第一条可用消息;
join 和 multitype join:等待从一组源中接收所有消息,然后将这些消息组合成一条消息,供另一个消息块使用;
timer:按固定的间隔向目标块发送消息;
这些消息块类型具有不同的特征,使其适用于不同的情况。 下面是部分特征:
- 传播类型:消息块是充当数据源、数据接收方还是两者;
- 消息顺序:消息块是否保留发送或接收消息的原始顺序。 每个预定义的消息块类型都会保留其发送或接收消息的原始顺序;
- 源计数:消息块可从中读取的最大源数;
- 目标计数:消息块可以写入到的最大目标数;
下表显示了这些特征与各种消息块类型的关系。
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