Asynchroniczne blokuje wiadomości
Biblioteka agentów zawiera kilka typów bloku komunikatów, które umożliwiają propagować wiadomości między składnikami aplikacji w sposób bezpieczny dla wątku.Te typy bloku komunikatów są często używane z różnych procedur przekazywania wiadomości, takich jak concurrency::send, concurrency::asend, concurrency::receive, i concurrency::try_receive.Aby uzyskać więcej informacji dotyczących przekazywania procedur, które są zdefiniowane przez bibliotekę agentów wiadomości, zobacz Funkcji przekazywania wiadomości.
Sekcje
Ten temat zawiera następujące sekcje:
Źródła i cele
Propagacja wiadomości
Omówienie typów blok wiadomości
Klasa unbounded_buffer
Klasa overwrite_buffer
Klasa single_assignment
wywołanie klasy
Transformator klasy
Wybór klasy
Klasy sprzężenia i multitype_join
Timer, klasa
Filtrowanie wiadomości
Rezerwacja wiadomości
Źródła i cele
Źródła i obiekty docelowe są dwa ważne uczestnikami przekazywania wiadomości.A źródło odnosi się do punktu końcowego komunikacji, który wysyła wiadomości.A docelowej odnosi się do punktu końcowego komunikacji, który odbiera wiadomości.Można traktować źródło jako punkt końcowy, który można odczytać i cel jako punkt końcowy, który możesz zapisywać.Aplikacje połączyć źródeł i cele razem formularz sieciami wiadomości.
Biblioteka agentów używa dwóch klas abstrakcyjnych do reprezentowania źródeł i obiektów docelowych: concurrency::ISource i concurrency::ITarget.Blok komunikatów typy tego aktu jak źródeł pochodzić od ISource; blok komunikatów typy tego aktu jak cele pochodzić od ITarget.Blok komunikatów typy tego aktu jako źródeł i obiektów docelowych wynikają z obu ISource i ITarget.
Top
Propagacja wiadomości
Komunikat propagacji jest wysyłanie wiadomości z jednego składnika do innego aktu.Po bloku komunikatu oferowana jest wiadomość, go zaakceptować, odrzucić lub odroczenie tej wiadomości.Każdy typ bloku komunikatu przechowuje i przesyła wiadomości na różne sposoby.Na przykład unbounded_buffer klasy przechowuje nieograniczoną liczbę wiadomości, overwrite_buffer klasy pojedynczej wiadomości są przechowywane w czasie i klasy transformer przechowuje wersji zmienionej w każdej wiadomości.Te typy bloku komunikatu są opisane bardziej szczegółowo w dalszej części tego dokumentu.
Po bloku komunikatu akceptuje wiadomość, go można opcjonalnie wykonywania pracy i, jeśli blok komunikatów jest źródłem, przekazać wynikowy wiadomości do innego członka sieci.Bloku komunikatów można użyć funkcji filtru odrzucić wiadomości, które chcesz otrzymywać.Filtry są opisane bardziej szczegółowo w dalszej części tego tematu, w sekcji Filtrowanie wiadomości.Bloku komunikatu, który odkłada wiadomości można zarezerwować tej wiadomości i zużywają go później.Rezerwacji wiadomości jest opisany bardziej szczegółowo w dalszej części tego tematu, w sekcji Rezerwacji komunikat.
Biblioteki agentów umożliwia bloki komunikatów do asynchronicznie lub synchronicznie przekazywania wiadomości.Kiedy przekazuje wiadomość do bloku komunikatu synchronicznie, na przykład za pomocą send funkcji środowiska wykonawczego blokuje bieżącego kontekstu, aż do bloku docelowego akceptuje lub odrzuca wiadomość.Kiedy przekazuje wiadomość do bloku komunikatu asynchronicznie, na przykład za pomocą asend funkcji środowiska wykonawczego oferuje wiadomości do obiektu docelowego i jeśli obiekt docelowy zaakceptuje wiadomość, środowiska wykonawczego planuje zadanie asynchroniczne, które propaguje wiadomości dla odbiorcy.Środowisko wykonawcze używa lekkie zadania do propagowania wiadomości w sposób współpracy.Aby uzyskać więcej informacji o zadaniach lekkie, zobacz Harmonogram zadań (współbieżności Runtime).
Aplikacje łączenia źródeł i cele do formularza wiadomości w sieci.Zazwyczaj łącze sieciowe i wywołanie send lub asend do przekazywania danych do sieci.Połączyć bloku komunikatu źródłowego do obiektu docelowego, call concurrency::ISource::link_target metody.Aby rozłączyć się z obiektem docelowym bloku źródłowego, wywołanie concurrency::ISource::unlink_target metody.Aby rozłączyć bloku źródłowego wszystkie elementy docelowe, call concurrency::ISource::unlink_targets metody.Jeden z typów bloku komunikatu wstępnie pozostawia lub jest niszczony, go automatycznie rozłącza sobie z bloków docelowych.Niektóre typy bloku komunikatu ograniczyć maksymalną liczbę obiektów docelowych, które można zapisywać.W poniższej sekcji opisano ograniczenia, które stosuje się do wiadomości wstępnie zdefiniowanych typów bloku.
Top
Omówienie typów blok wiadomości
W poniższej tabeli opisano pokrótce roli typów ważne bloku komunikatów.
unbounded_buffer
Są przechowywane kolejki wiadomości.overwrite_buffer
Przechowuje jednej wiadomości, które mogą być zapisywane i odczytać wiele razy.single_assignment
Przechowuje jednej wiadomości, które mogą być zapisywane jednokrotnie i odczytać wiele razy.Wywołanie
Wykonuje pracę po odebraniu wiadomości.Transformator
Wykonuje pracę, jeśli odbieranych danych i wysyła wynik tej pracy do innego bloku docelowego.transformer Klasy może działać w różnych danych wejściowych i typy danych wyjściowych.Wybór
Zaznacza pierwszy komunikat dostępne z zestawu źródeł.sprzężenia i sprzężenie multitype
Poczekaj, aż wszystkie wiadomości być odbierane z zestawu źródeł, a następnie połączyć wszystkie wiadomości w jednej wiadomości do innego bloku komunikatów.Czasomierz
Wysyła wiadomość do bloku docelowego w regularnych odstępach czasu.
Te typy bloku komunikatów mają różne parametry, które były przydatne w różnych sytuacjach.Są to właściwości:
Propagacja typu: czy bloku komunikatu działa jako źródło danych lub odbiornik danych.
Porządkowanie wiadomości: czy bloku komunikatu utrzymuje oryginalnego zamówienia wysłane lub odebrane wiadomości.Każdego typu bloku komunikatu wstępnie zdefiniowane zachowuje oryginalnego zamówienia, w którym wysyła lub odbiera wiadomości.
Licznik źródła: Maksymalna liczba źródeł, które można odczytać bloku komunikatów.
Docelowe licznik: Maksymalna liczba obiektów docelowych, które można zapisać blok komunikatów.
W poniższej tabeli przedstawiono, jak cechy te odnoszą się do różnych typów bloku komunikatów.
Typ bloku komunikatu |
Typ propagacji (źródło, docelowych lub oba) |
Komunikat zamawiania (zamówione lub Unordered) |
Licznik źródła |
Licznik docelowej |
---|---|---|---|---|
unbounded_buffer |
Zarówno |
Zamówione |
O nieokreślonej długości |
O nieokreślonej długości |
overwrite_buffer |
Zarówno |
Zamówione |
O nieokreślonej długości |
O nieokreślonej długości |
single_assignment |
Zarówno |
Zamówione |
O nieokreślonej długości |
O nieokreślonej długości |
call |
Docelowe |
Zamówione |
O nieokreślonej długości |
Nie dotyczy |
transformer |
Zarówno |
Zamówione |
O nieokreślonej długości |
1 |
choice |
Zarówno |
Zamówione |
10 |
1 |
join |
Zarówno |
Zamówione |
O nieokreślonej długości |
1 |
multitype_join |
Zarówno |
Zamówione |
10 |
1 |
timer |
Źródła |
Nie dotyczy |
Nie dotyczy |
1 |
Poniżej opisano typy bloku komunikatów bardziej szczegółowo.
Top
Klasa unbounded_buffer
Concurrency::unbounded_buffer klasy reprezentuje ogólnego przeznaczenia struktury asynchronicznego przesyłania wiadomości.Ta klasa przechowuje pierwszy w pierwszym FIFO kolejki komunikatów, które są napisane przez wiele źródeł lub odczytać przez wiele elementów docelowych.Gdy element docelowy otrzymuje wiadomość z unbounded_buffer obiektów, że wiadomość jest usuwana z kolejki wiadomości.Dlatego chociaż unbounded_buffer obiekt może mieć wiele elementów docelowych, tylko jeden obiekt docelowy zostanie wyświetlony każdy komunikat.unbounded_buffer Klasy jest przydatne, gdy chcesz przekazać wiele wiadomości do innego składnika, a składnik ten musi otrzymać każdej wiadomości.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z unbounded_buffer klasy.W tym przykładzie wysyła trzy wartości do unbounded_buffer obiekt, a następnie odczytuje wartości z tego samego obiektu.
// 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;
}
Ten przykład generuje następujące wyniki:
33
44
55
Na przykład pełną, która pokazuje, jak użyć unbounded_buffer klasy, zobacz Jak: wdrożenia różnych wzorców producentów i konsumentów.
Top
Klasa overwrite_buffer
Concurrency::overwrite_buffer podobny do klasy unbounded_buffer klasy, z wyjątkiem overwrite_buffer obiektu przechowuje tylko jednej wiadomości.Ponadto, kiedy element docelowy otrzyma wiadomość od overwrite_buffer obiektu tej wiadomości nie jest usuwany z bufora.W związku z tym wiele elementów docelowych otrzymać kopię wiadomości.
overwrite_buffer Klasy jest przydatne, gdy chcesz przekazać wiele wiadomości do innego składnika, ale składnik ten musi jedynie najbardziej aktualne wartości.Tej klasy jest również przydatne, gdy chcesz emitować wiadomość do wielu składników.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z overwrite_buffer klasy.W tym przykładzie wysyła trzy wartości do overwrite _buffer obiekt, a następnie odczytuje wartości bieżącej z tego samego obiektu trzy razy.W tym przykładzie jest podobne do przykładu dla unbounded_buffer klasy.Jednakże overwrite_buffer klasy przechowuje tylko jednej wiadomości.Ponadto środowiska wykonawczego nie usuwa wiadomości z overwrite_buffer obiekt po jego odczytaniem.
// 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;
}
Ten przykład generuje następujące wyniki:
55
55
55
Na przykład pełną, która pokazuje, jak użyć overwrite_buffer klasy, zobacz Jak: wdrożenia różnych wzorców producentów i konsumentów.
Top
Klasa single_assignment
Concurrency::single_assignment podobny do klasy overwrite_buffer klasy, z wyjątkiem single_assignment obiektu mogą być zapisywane tylko raz.Podobnie jak overwrite_buffer klasy, gdy cel odbiera wiadomość z single_assignment obiektów, że wiadomość nie jest usuwany z tego obiektu.W związku z tym wiele elementów docelowych otrzymać kopię wiadomości.single_assignment Klasy jest przydatne, gdy chcesz emitować wiadomości jeden do wielu składników.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z single_assignment klasy.W tym przykładzie wysyła trzy wartości do single_assignment obiekt, a następnie odczytuje wartości bieżącej z tego samego obiektu trzy razy.W tym przykładzie jest podobne do przykładu dla overwrite_buffer klasy.Chociaż zarówno overwrite_buffer i single_assignment klasy przechowywanie pojedynczej wiadomości, single_assignment klasy mogą być zapisywane tylko raz.
// 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;
}
Ten przykład generuje następujące wyniki:
33
33
33
Na przykład pełną, która pokazuje, jak użyć single_assignment klasy, zobacz Instruktaż: Wykonawczych prognoz.
Top
wywołanie klasy
Concurrency::call klasa działa jako odbiorca wiadomości, pełniący funkcję pracy, gdy odbiera dane.Ta funkcja pracy może być wyrażenie lambda, obiekt funkcji lub wskaźnik funkcji.A call obiektu zachowuje się inaczej niż wywołanie funkcji zwykłych, ponieważ działa równolegle z innymi składnikami, które do niej wysyłać wiadomości.Jeśli call obiektu wykonuje pracę po odebraniu wiadomości, dodaje tej wiadomości do kolejki.Każdy call procesów obiektu w kolejce wiadomości w kolejności, w jakiej zostały odebrane.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z call klasy.To przykładowe polecenie tworzy call obiekt, który drukuje każdej wartości, które otrzymuje w konsoli.Przykład wysyła następnie trzy wartości do call obiektu.Ponieważ call obiektu przetwarza wiadomości w osobnym wątku, w tym przykładzie użyto również zmienną licznika i zdarzenia obiektu w celu zapewnienia, że call obiektu przetwarza wszystkie wiadomości przed wmain zwraca działać.
// 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();
}
Ten przykład generuje następujące wyniki:
33
44
55
Na przykład pełną, która pokazuje, jak użyć call klasy, zobacz Jak: zapewniają funkcje pracy do wywołania i transformator klas.
Top
Transformator klasy
Concurrency::transformer klasa działa jako zarówno odbiornik wiadomości i nadawcy wiadomości.transformer Podobny do klasy call klasy, ponieważ wykonuje funkcję pracy użytkownika, po otrzymaniu danych.Jednakże transformer klasy również wysyła wynik funkcji pracy obiektów odbiornika.Podobnie jak call obiektu, transformer obiektu działa równolegle z innymi składnikami, które do niej wysyłać wiadomości.Jeśli transformer obiektu wykonuje pracę po odebraniu wiadomości, dodaje tej wiadomości do kolejki.Każdy transformer obiektu przetwarza jego wiadomości z kolejki w kolejności, w jakiej zostały odebrane.
transformer Klasy wysyła swoje wiadomości do jednego obiektu docelowego.Jeśli ustawisz _PTarget parametr do konstruktora NULL, później można określić lokalizację docelową, wywołując concurrency::link_target metody.
W przeciwieństwie do wszystkich innych asynchronicznego bloku typy wiadomości, które są dostarczane przez biblioteki agentów transformer klasy może działać w różnych danych wejściowych i typy danych wyjściowych.Możliwość przekształcania danych z jednego typu do innego powoduje, że transformer klasy kluczowym elementem w wielu sieciach współbieżnych.Ponadto można dodać więcej funkcji równolegle szczegółowymi w funkcji pracy transformer obiektu.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z transformer klasy.To przykładowe polecenie tworzy transformer obiektów, że dane wejściowe wielokrotności każdego int wartość przez 0,33 do produkcji double wartości jako dane wyjściowe.Przykład otrzyma następnie przekształconych wartości z tego samego transformer obiektu i drukuje je do konsoli.
// 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;
}
Ten przykład generuje następujące wyniki:
10.89
14.52
18.15
Na przykład pełną, która pokazuje, jak użyć transformer klasy, zobacz Jak: wykorzystanie transformer planowanej danych.
Top
Wybór klasy
Concurrency::choice klasy wybiera pierwszy komunikat dostępne z zestawu źródeł.choice Klasy reprezentuje mechanizm kontroli przepływu zamiast mechanizm przepływ danych (temat Biblioteka agentów asynchroniczne w tym artykule opisano różnice między przepływ danych i sterowania przepływem).
Odczyt z obiektu wybór przypomina wywołanie funkcji Windows API WaitForMultipleObjects , gdy posiada bWaitAll ustawiono parametr FALSE.Jednakże choice klasy wiąże sam zamiast zdarzeń do obiektu zewnętrznego synchronizacji danych.
Zazwyczaj należy używać choice klasy wraz z concurrency::receive funkcja kierowania przepływ sterowania w aplikacji.Użyj choice klasy, gdy trzeba wybierać buforów wiadomości, które mają różne typy.Użyj single_assignment klasy, gdy trzeba wybierać buforów wiadomości, które mają ten sam typ.
Kolejność, w którym można połączyć źródeł do choice obiektu jest ważne, ponieważ można określić, jaki komunikat jest zaznaczone.Na przykład, Rozważmy przypadek gdzie połączyć kilka buforów wiadomości zawierające wiadomość do choice obiektu.choice Obiektu wybiera pierwsze źródło, połączoną z wiadomości.Po dołączeniu wszystkich źródeł, choice obiektu zachowuje kolejności, w której każde źródło odbiera wiadomość.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z choice klasy.W tym przykładzie concurrency::make_choice funkcja tworzenia choice obiekt, który wybiera się spośród trzech bloków komunikatów.Przykład następnie oblicza różnych liczb Fibonacciego i zapisuje wynik każdego bloku różnych komunikatów.Przykład drukuje do konsoli następnie komunikat, który jest oparty na operację, która zajęła pierwsze.
// 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;
}
}
Ten przykład generuje następujące przykładowe dane wyjściowe:
fib35 received its value first. Result = 9227465
Ponieważ zadanie, które oblicza 35cz Fibonacciego nie jest gwarantowane najpierw zakończenie, dane wyjściowe tego przykładu mogą się różnić.
W tym przykładzie concurrency::parallel_invoke algorytm obliczania liczby Fibonacciego równolegle.Aby uzyskać więcej informacji o parallel_invoke, zobacz Algorytmy równoległe.
Na przykład pełną, która pokazuje, jak użyć choice klasy, zobacz Jak: wybranie zadania ukończone.
Top
Klasy sprzężenia i multitype_join
Concurrency::join i concurrency::multitype_join klasy pozwalają oczekiwania dla każdego elementu członkowskiego zestawu źródeł otrzymać wiadomość.join Aktów klasy obiektów źródła, które mają wspólną typ wiadomości.multitype_join Aktów klasy obiektów źródła, które mogą mieć różne rodzaje komunikatów.
Odczyt z join lub multitype_join obiekt podobny do wywołania funkcji API systemu Windows WaitForMultipleObjects , gdy posiada bWaitAll ustawiono parametr TRUE.Jednakże, podobnie jak choice obiektu, join i multitype_join obiektów, użyj mechanizmu zdarzenia, która wiąże sam zamiast zdarzeń do obiektu zewnętrznego synchronizacji danych.
Odczyt z join tworzy obiekt std::vector obiektu.Odczyt z multitype_join tworzy obiekt std::tuple obiektu.Elementy wyświetlane w tych obiektów w tej samej kolejności, w ich odpowiednich buforów źródła są połączone z join lub multitype_join obiektu.Ponieważ w kolejności, w której łącze jest źródło buforów do join lub multitype_join obiekt jest skojarzony z zamówieniem elementów w wynikowym vector lub tuple obiektów, zaleca się, że nie odłączyć istniejący buforu źródłowego z sprzężenia.Ten sposób może spowodować zachowanie nieokreślona.
Sowa kontra-sowa sprzężeń
join i multitype_join klasy wsparcie koncepcji sowa i sowa sprzężenia.A sprzężenia sowa akceptuje wiadomości z każdego źródła wiadomości stają się dostępne, dopóki wszystkie wiadomości są dostępne.A - sowa sprzężenia odbiera wiadomości w dwóch fazach.Po pierwsze-sowa sprzężenia czeka, dopóki jest on oferowany wiadomości z każdego źródła.Po drugie po wszystkich wiadomości źródłowych są dostępne, sprzężenia sowa próbuje rezerwy te wiadomości.Jeśli można ją zarezerwować każdej wiadomości, zużywa wszystkie wiadomości i propaguje je do swoich docelowych.W przeciwnym razie wydania, ani anuluje zastrzeżenia wiadomości i ponownie czeka na komunikat każdego źródła.
Sprzężenia sowa wykonać lepiej niż-sowa sprzężenia, ponieważ one niezwłocznie akceptować wiadomości.Jednak w rzadkich przypadkach sowa sprzężeń może prowadzić do zakleszczeń.Gdy wielu sprzężeń, zawierających jeden lub więcej obiektów udostępnionych źródła, należy użyć sprzężenia sowa.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z join klasy.W tym przykładzie concurrency::make_join funkcja tworzenia join obiekt, który odbiera z trzech single_assignment obiektów.Ten przykład oblicza różnych liczb Fibonacciego, zapisuje każdy wynik w innym single_assignment obiekt, a następnie drukuje konsoli każdego powoduje, że join obiekt posiada.W tym przykładzie jest podobne do przykładu dla choice klasy, z wyjątkiem join klasy czeka, aż wszystkie bloki komunikatów źródła otrzymać wiadomość.
// 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;
}
Ten przykład generuje następujące wyniki:
fib35 = 9227465
fib37 = 24157817
half_of_fib42 = 1.33957e+008
W tym przykładzie concurrency::parallel_invoke algorytm obliczania liczby Fibonacciego równolegle.Aby uzyskać więcej informacji o parallel_invoke, zobacz Algorytmy równoległe.
Kompletne przykłady, które pokazują, jak używać join klasy, zobacz Jak: wybranie zadania ukończone i Instruktaż: Za pomocą sprzężenia, aby zapobiec zakleszczenia.
Top
Timer, klasa
Concurrency::timer klasa działa jako źródło wiadomości.A timer obiekt wysyła wiadomość do obiektu docelowego, po upływie określonego okresu czasu.timer Klasy jest przydatne, gdy należy opóźnić wysłanie wiadomości lub chcesz wysłać wiadomość w regularnych odstępach czasu.
timer Klasy wysyła jego wiadomość tylko jeden obiekt docelowy.Jeśli ustawisz _PTarget parametr do konstruktora NULL, później można określić lokalizację docelową, wywołując concurrency::ISource::link_target metody.
A timer obiektu powtarzanych lub niepowtarzalny.Aby utworzyć czasomierza powtarzanej, należy przekazać true do _Repeating parametr podczas wywołania konstruktora.W przeciwnym razie przekazać false dla _Repeating parametr utworzyć czasomierza niepowtarzającym.Jeśli zegar jest powtarzana, wysyła tę samą widomość do jego docelowego po upływie każdego interwału.
Tworzy bibliotekę agenci timer obiektów w stanie nie jest uruchomiona.Aby uruchomić obiektu timer, wywołanie concurrency::timer::start metody.Aby zatrzymać timer obiektów, zniszczenie obiektu lub wywołanie concurrency::timer::stop metody.Wstrzymać powtarzanej timer, call concurrency::timer::pause metody.
Przykład
Poniższy przykład pokazuje podstawową strukturę jak pracować z timer klasy.W przykładzie użyto timer i call obiekty do raportowania postępu czasochłonnych operacji.
// 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;
}
Ten przykład generuje następujące przykładowe dane wyjściowe:
Computing fib(42)..................................................
result is 267914296
Na przykład pełną, która pokazuje, jak użyć timer klasy, zobacz Jak: wysyłanie wiadomości w regularnych odstępach czasu..
Top
Filtrowanie wiadomości
Podczas tworzenia obiektu bloku komunikatu może dostarczyć funkcji filtru Określa, czy blok komunikatów akceptuje lub odrzuca wiadomość.Funkcja filtr jest przydatny sposób, aby zagwarantować, że blok wiadomości odbiera tylko niektóre wartości.
Następujący przykład przedstawia sposób tworzenia unbounded_buffer obiekt, który używa funkcji filtru do akceptowania wyłącznie liczby parzyste.unbounded_buffer Obiekt odrzuca nieparzystej liczby i dlatego nie propaguje numery nieparzyste jego bloków docelowych.
// 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;
}
}
Ten przykład generuje następujące wyniki:
0 2 4 6 8
Funkcja filtrowania może być funkcji lambda, wskaźnik funkcji lub obiekt funkcji.Każda funkcja filtru przyjmuje jedną z następujących form.
bool (_Type)
bool (_Type const &)
Aby wyeliminować zbędne kopiowanie danych, przy drugim formularzu Typ agregacji, które są propagowane przez wartość.
Obsługuje filtrowanie wiadomości Przepływ model programowania, w którym składniki są wykonywane obliczenia po otrzymaniu danych.Przykłady, które sterowania przepływem danych w sieci przekazywania wiadomości przy użyciu funkcji filtrowania, zobacz Jak: Filtr bloku komunikatu, Instruktaż: Tworzenie agenta przepływ danych, i Instruktaż: Tworzenie sieci przetwarzania obrazu.
Top
Rezerwacja wiadomości
Komunikat rezerwacji umożliwia bloku komunikatu zarezerwować wiadomości do późniejszego użycia.Zazwyczaj rezerwacji wiadomości nie jest używany bezpośrednio.Jednak komunikat zrozumienia rezerwacji może pomóc lepiej zrozumieć zachowanie pewnych typów wiadomości wstępnie bloku.
Należy wziąć pod uwagę-sowa i intensywnie sprzężenia.Oba te Użyj rezerwacji wiadomości zarezerwować wiadomości do późniejszego użycia.Opisane wcześniej, sprzężenia sowa odbiera wiadomości w dwóch fazach.Podczas pierwszej fazy non sknerus join obiektu czeka na każdy z jej źródeł do odbierania wiadomości.Sowa sprzężenia próbuje następnie rezerwy te wiadomości.Jeśli można ją zarezerwować każdej wiadomości, zużywa wszystkie wiadomości i propaguje je do swoich docelowych.W przeciwnym razie wydania, ani anuluje zastrzeżenia wiadomości i ponownie czeka na komunikat każdego źródła.
Sowa sprzężenia odczytuje również komunikaty wejściowe z wielu źródeł, używa komunikatu rezerwacji odczytać dodatkowe wiadomości podczas oczekiwania na otrzymanie komunikatu z każdego źródła.Na przykład, rozważmy sowa sprzężenia, która odbiera komunikaty z bloków komunikatów A i B.Jeśli sprzężenie sowa otrzymuje dwa komunikaty z B, ale nie otrzymał jeszcze wiadomości od A, intensywnie sprzężenia zapisuje komunikat unikatowy identyfikator drugi komunikat z B.Po sowa sprzężenia odbiera wiadomość z A i propaguje te wiadomości używa identyfikatora zapisane wiadomości czy drugi komunikat z B jest nadal dostępny.
Podczas implementowania własne typy bloku niestandardowy komunikat, można użyć wiadomości rezerwacji.Na przykład o tworzeniu niestandardowego komunikatu typu bloku, zobacz Instruktaż: Tworzenie bloku komunikatów niestandardowych.
Top