Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Библиотека агентов предоставляет несколько типов блоков сообщений, которые позволяют распространять сообщения между компонентами приложения в потокобезопасном режиме. Эти типы блоков сообщений часто используются с различными подпрограммами передачи сообщений, такими как concurrency::send, concurrency::asend, concurrency::receive и concurrency::try_receive. Дополнительные сведения о подпрограммах передачи сообщений, определенных библиотекой агентов, см. в разделе "Функции передачи сообщений".
Разделы
Этот раздел состоит из следующих подразделов.
Источники и цели
Источники и целевые объекты являются двумя важными участниками передачи сообщений. Источник ссылается на конечную точку связи, которая отправляет сообщения. Целевой объект ссылается на конечную точку связи, которая получает сообщения. Вы можете рассматривать источник как конечную точку, из которую вы читаете и целевой объект как конечную точку, в которую вы записываете. Приложения подключают источники и целевые объекты вместе для формирования сетей обмена сообщениями.
Библиотека агентов использует два абстрактных класса для представления источников данных и целевых объектов: конкуррентность::ISource и конкуррентность::ITarget. Типы блоков сообщений, которые действуют как источники, производные от ISource; типы блоков сообщений, которые действуют в качестве целевых объектов, производных от ITarget. Типы блоков сообщений, которые действуют как источники и приемники, производные от ISource и ITarget.
[В начало]
Распространение сообщений
Распространение сообщений — это действие отправки сообщения из одного компонента в другой. Когда блоку сообщений предлагается сообщение, он может его принять, отклонить или отложить. Каждый тип блока сообщений хранит и передает сообщения разными способами. Например, unbounded_buffer класс хранит неограниченное количество сообщений, overwrite_buffer класс хранит одно сообщение одновременно, а класс преобразователя сохраняет измененную версию каждого сообщения. Эти типы блоков сообщений подробно описаны далее в этом документе.
Если блок сообщений принимает сообщение, он может при необходимости выполнить задачу. Если блок сообщений является источником, он может передать полученное сообщение другому участнику сети. Блок сообщений может использовать функцию фильтра для отклонения сообщений, которые он не хочет получать. Фильтры подробно описаны далее в этом разделе в разделе "Фильтрация сообщений". Блок сообщения, откладывающий сообщение, может зарезервировать это сообщение и использовать его позже. Резервирование сообщений подробно описано далее в этом разделе в разделе "Резервирование сообщений".
Библиотека агентов позволяет блокам сообщений асинхронно или синхронно передавать сообщения. При передаче сообщения блоку сообщения синхронно, например с помощью send функции, среда выполнения блокирует текущий контекст, пока целевой блок не принимает или отклоняет сообщение. При передаче сообщения в блок сообщений асинхронно, например с помощью asend функции, среда выполнения предлагает сообщение целевому объекту, а если целевой объект принимает сообщение, среда выполнения планирует асинхронную задачу, которая распространяет сообщение получателю. Среда выполнения использует упрощенные задачи для совместного распространения сообщений. Дополнительные сведения о упрощенных задачах см. в разделе Планировщик задач.
Приложения подключают источники и целевые объекты вместе для формирования сетей обмена сообщениями. Как правило, вы подключаете сеть и вызываете send или asend, чтобы передать данные в сеть. Чтобы подключить блок исходного сообщения к целевому объекту, вызовите метод concurrency::ISource::link_target. Чтобы отключить исходный блок от целевого объекта, вызовите метод concurrency::ISource::unlink_target . Чтобы отсоединить исходный блок от всех его целевых объектов, вызовите метод concurrency::ISource::unlink_targets. Если один из стандартных типов блоков сообщений покидает область действия или уничтожается, он автоматически отключается от любых целевых блоков. Некоторые типы блоков сообщений ограничивают максимальное количество целевых блоков, в которые они могут записывать данные. В следующем разделе описываются ограничения, которые применяются к предопределенным типам блоков сообщений.
[В начало]
Общие сведения о типах блоков сообщений
В следующей таблице кратко описывается роль важных типов блоков сообщений.
unbounded_buffer
Хранит очередь сообщений.
буфер_перезаписи
Сохраняет одно сообщение, которое можно записать в несколько раз и прочитать.
однократное присваивание
Сохраняет сообщение, которое можно записать один раз и читать несколько раз.
вызов
Выполняет работу при получении сообщения.
трансформатор
Выполняет работу при получении данных и отправляет результат этой работы в другой целевой блок. Класс transformer может работать с различными типами входных и выходных данных.
выбор
Выбирает первое доступное сообщение из набора источников.
присоединение и многотипное соединение
Дождитесь получения всех сообщений из набора источников, а затем объедините сообщения в одно сообщение для другого блока сообщений.
таймер
Отправляет сообщение целевому блоку через регулярный интервал.
Эти типы блоков сообщений имеют различные характеристики, которые позволяют использовать их для различных ситуаций. Ниже приведены некоторые характеристики:
Тип распространения: является ли блок сообщения источником данных, приемником данных или обоими.
Порядок сообщений: поддерживает ли блок сообщения исходный порядок отправки или получения сообщений. Каждый предопределенный тип блока сообщений сохраняет исходный порядок отправки или получения сообщений.
Число источников: максимальное количество источников, из которых блок сообщений может считываться.
Число целевых объектов: максимальное число целевых объектов, в которые блок сообщений может записываться.
В следующей таблице показано, как эти характеристики связаны с различными типами блоков сообщений.
| Тип блока сообщений | Тип распространения (источник, целевой объект или оба) | Упорядочение сообщений (упорядочено или неупорядочено) | Число источников | Число целевых объектов |
|---|---|---|---|---|
unbounded_buffer |
Оба | Заказано | Неограниченный | Неограниченный |
overwrite_buffer |
Оба | Заказано | Неограниченный | Неограниченный |
single_assignment |
Оба | Заказано | Неограниченный | Неограниченный |
call |
Цель | Заказано | Неограниченный | Н/Д |
transformer |
Оба | Заказано | Неограниченный | 1 |
choice |
Оба | Заказано | 10 | 1 |
join |
Оба | Заказано | Неограниченный | 1 |
multitype_join |
Оба | Заказано | 10 | 1 |
timer |
Источник | Н/Д | Н/Д | 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. Хотя оба 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;
}
В примере получается следующий вывод.
333333
Полный пример использования single_assignment класса см. в пошаговом руководстве. Реализация фьючерсов.
[В начало]
Класс call
Класс concurrency::call выступает в качестве приемника сообщений, выполняющего рабочую функцию при получении данных. Эта рабочая функция может быть лямбда-выражением, объектом функции или указателем функции.
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 класс выступает как получатель сообщений, так и отправитель сообщений. Класс 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
Полный пример использования transformer класса см. в разделе "Практическое руководство. Использование преобразователя в конвейере данных".
[В начало]
Класс выбора
Класс конкурентности::choice выбирает первое доступное сообщение из сетки источников. Класс choice представляет механизм потока управления вместо механизма потока данных (в разделе "Библиотека асинхронных агентов" описывает различия между потоком данных и потоком управления).
Чтение из объекта выбора напоминает вызов функции API Windows WaitForMultipleObjects, когда параметр bWaitAll установлен на FALSE.
choice Однако класс привязывает данные к самому событию, а не к внешнему объекту синхронизации.
Как правило, вы используете класс choice вместе с функцией concurrency::receive для управления потоком выполнения в вашем приложении.
choice Используйте класс, когда нужно выбрать между буферами сообщений, имеющими разные типы.
single_assignment Используйте класс, когда нужно выбрать один и тот же тип буферов сообщений.
Порядок связывания источников с choice объектом важен, так как он может определить, какое сообщение выбрано. Например, рассмотрим случай, когда вы связываете несколько буферов сообщений, которые уже содержат сообщение с choice объектом. Объект choice выбирает сообщение из первого источника, к которому он связан. После связывания всех источников объект choice сохраняет порядок, в котором каждый источник получает сообщение.
Пример
В следующем примере показана базовая структура работы с классом 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;
}
}
В этом примере получается следующий пример вывода:
fib35 received its value first. Result = 9227465
Так как задача, вычисляющая 35-е число Фибоначчи, не гарантируется завершиться первой, выходные данные этого примера могут варьироваться.
В этом примере используется алгоритм concurrency::parallel_invoke для параллельного вычисления чисел Фибоначчи. Дополнительные сведения см. в parallel_invokeразделе "Параллельные алгоритмы".
Полный пример использования choice класса см. в разделе "Практическое руководство. Выбор среди завершенных задач".
[В начало]
Классы join и multitype_join
Классы concurrency::join и concurrency::multitype_join позволяют ожидать получения сообщений от каждого члена набора источников. Класс join действует на исходных объектах, имеющих общий тип сообщения. Класс multitype_join действует на исходных объектах, которые могут иметь разные типы сообщений.
Чтение из объекта join или multitype_join напоминает вызов функции WaitForMultipleObjects API Windows, когда параметр bWaitAll установлен в TRUE. Однако, так же как и choice объект, объекты join и multitype_join используют механизм событий, который привязывает данные к самому событию, а не к внешнему объекту синхронизации.
Чтение из join объекта создает объект std::vector . Чтение из multitype_join объекта создает объект std::tuple . Элементы отображаются в этих объектах в том же порядке, в каком их соответствующие исходные буферы связываются с объектом join или multitype_join. Так как порядок связывания исходных буферов с join объектом или multitype_join объектом связан с порядком элементов в результирующем vector или tuple объекте, рекомендуется не связывать существующий исходный буфер из соединения. Это может привести к неуказанному ведению.
Жадные и нежадные (или ленивые) соединения
Классы joinmultitype_join поддерживают концепцию жадных и не жадных соединений.
Жадное соединение принимает сообщение из каждого из источников по мере того как сообщения становятся доступными до тех пор, пока все сообщения не будут доступны. Не жадное соединение получает сообщения на двух этапах. Во-первых, не жадное соединение ожидает, пока оно не будет предложено сообщение от каждого из его источников. Во-вторых, после того как все исходные сообщения доступны, не жадное присоединение пытается зарезервировать каждый из этих сообщений. Если он может зарезервировать каждое сообщение, он потребляет все сообщения и распространяет их на целевой объект. В противном случае он освобождает или отменяет резервирование сообщений и снова ожидает получения каждого источника сообщения.
Жадные соединения выполняются лучше, чем не жадные соединения, так как они принимают сообщения немедленно. Однако в редких случаях жадные объединения могут привести к взаимоблокировкам. Используйте не жадное соединение при наличии нескольких соединений, содержащих один или несколько общих исходных объектов.
Пример
В следующем примере показана базовая структура работы с классом join . В этом примере функция concurrency::make_join используется для создания объекта join, который получает данные от трех объектов single_assignment. В этом примере вычисляются различные числа Фибоначчи, каждый результат хранится в другом 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 для параллельного вычисления чисел Фибоначчи. Дополнительные сведения см. в parallel_invokeразделе "Параллельные алгоритмы".
Полные примеры использования join класса см. в разделе "Практическое руководство. Выбор между завершенными задачами и пошаговое руководство. Использование соединения для предотвращения взаимоблокировки".
[В начало]
Класс timer
Класс concurrency.timer действует как источник сообщений.
timer Объект отправляет сообщение целевому объекту после истечения указанного периода времени. Класс timer полезен, если необходимо отложить отправку сообщения или отправить сообщение через регулярный интервал.
Класс timer отправляет сообщение только одному целевому объекту. Если в конструкторе параметр _PTarget задан в значение NULL, позже можно указать целевой объект, вызвав метод concurrency::ISource::link_target.
Объект timer может повторяться или не повторяться. Чтобы создать повторяющийся таймер, передайте true в качестве параметра _Repeating при вызове конструктора. В противном случае передайте false в параметр _Repeating, чтобы создать таймер, который не повторяется. Если таймер повторяется, он отправляет одно и то же сообщение в целевой объект после каждого интервала.
Библиотека агентов создает 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
Полный пример использования 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
Функция фильтра может быть лямбда-функцией, указателем функции или объектом функции. Каждая функция фильтра принимает одну из следующих форм.
bool (T)
bool (T const &)
Чтобы исключить ненужные копии данных, используйте вторую форму при наличии агрегатного типа, распространяемого по значению.
Фильтрация сообщений поддерживает модель программирования потока данных, в которой компоненты выполняют вычисления при получении данных. Примеры, использующие функции фильтрации для управления потоком данных в сети передачи сообщений, см. в статье "Практическое руководство. Использование фильтра блокировки сообщений", пошаговое руководство. Создание агента потока данных и пошаговое руководство. Создание сети обработки изображений.
[В начало]
Резервирование сообщений
Резервирование сообщений позволяет блоку сообщений зарезервировать сообщение для последующего использования. Как правило, резервирование сообщений не используется напрямую. Однако понимание резервирования сообщений поможет лучше понять поведение некоторых предопределенных типов блоков сообщений.
Рассмотрим не жадные и жадные соединения. Оба из них используют резервирование сообщений для резервирования сообщений для последующего использования. Ранее описанное нежадное соединение получает сообщения на двух этапах. На первом этапе не жадный join объект ожидает получения сообщения каждым из его источников. Затем нежадное соединение пытается зарезервировать каждое из этих сообщений. Если он может зарезервировать каждое сообщение, он потребляет все сообщения и распространяет их на целевой объект. В противном случае он освобождает или отменяет резервирование сообщений и снова ожидает получения каждого источника сообщения.
Жадное соединение, которое также считывает входные сообщения из ряда источников, использует резервирование сообщений для чтения дополнительных сообщений, пока ожидает получения сообщения из каждого источника. Например, рассмотрим жадное соединение, которое получает сообщения из блоков A сообщений и B. Если жадное соединение получает два сообщения из B, но еще не получено сообщение от A, жадное соединение сохраняет уникальный идентификатор сообщения для второго сообщения B. Когда жадное соединение получает сообщение от A и распространяет эти сообщения, оно использует сохраненный идентификатор сообщения, чтобы узнать, доступно ли второе сообщение от B.
При реализации собственных типов блоков сообщений можно использовать резервирование сообщений. Пример создания типа пользовательского блока сообщений см. в пошаговом руководстве. Создание настраиваемого блока сообщений.
[В начало]