Udostępnij za pośrednictwem


Bloki komunikatów asynchronicznych

Biblioteki agentów zawiera kilka typów bloków komunikatów, które pozwalają na propagowanie wiadomości między składnikami aplikacji w sposób wątków.Te typy bloku komunikatów są często używane z różnych procedur przekazywania wiadomości, takie jak concurrency::send, concurrency::asend, concurrency::receive, i concurrency::try_receive.Aby uzyskać więcej informacji na temat procedur, które są definiowane przez biblioteki agentów przekazywania wiadomości, zobacz Funkcje przekazywania komunikatów.

Sekcje

Ten temat zawiera następujące sekcje:

  • Źródła i obiekty docelowe

  • Propagacja komunikatów

  • Omówienie typów bloku komunikatu

  • Klasa unbounded_buffer

  • Klasa overwrite_buffer

  • Klasa single_assignment

  • Klasa wywołania

  • Klasa transformatora

  • Klasa wyboru

  • Klasy łączy oraz łączy typu multitype_join

  • Klasa czasomierza

  • Filtrowanie komunikatów

  • Zastrzeżenie komunikatu

Źródła i obiekty docelowe

Źródła i obiekty docelowe są dwa ważne uczestnicy przekazywanie komunikatów.A źródło odnosi się do punktu końcowego komunikacji, który wysyła wiadomości.A miejsce docelowe odnosi się do punktu końcowego komunikacji, która odbiera komunikaty.Można traktować źródło jako punkt końcowy, który należy odczytywać i cel jako punkt końcowy, pisanym w celu.Aplikacje połączyć źródła i cele razem do formularza sieciami wiadomości.

Biblioteki agentów używa dwóch klas abstrakcyjnych do reprezentowania źródła i obiekty docelowe: concurrency::ISource i concurrency::ITarget.Typy bloków wiadomości, które działają jako obiekty źródłowe wywodzą się z ISource; typy bloków wiadomości, które działają jako obiekty docelowe wywodzą się z ITarget.Blok komunikatów typy tego aktu jako źródła i cele pochodzić z obu ISource i ITarget.

[U góry]

Propagacja komunikatów

Komunikat propagacji polega na wysyłaniu wiadomości z jednego składnika do drugiego.Po bloku komunikatów jest oferowany wiadomości, to zaakceptować, odrzucić lub odroczyć tę wiadomość.Każdy typ bloku komunikatu przechowuje i przesyła wiadomości na różne sposoby.Na przykład unbounded_buffer klasa przechowuje nieograniczoną liczbę wiadomości, overwrite_buffer klasa przechowuje pojedynczą wiadomość w danej chwili i klasy transformator przechowywane zmienionych wersji każdej wiadomości.Te typy bloku wiadomości są opisane bardziej szczegółowo w dalszej części tego dokumentu.

Gdy bloku komunikatów akceptuje wiadomość, może opcjonalnie wykonywania pracy i, jeśli bloku komunikatów jest źródłem, przekazać komunikatu do innego członka sieci.Bloku komunikatów można użyć funkcji filtru, aby odrzucić wiadomości, których nie chce otrzymywać.Filtry są opisane bardziej szczegółowo w dalszej części tego tematu, w sekcji Filtrowanie wiadomości.Bloku komunikatów, który odkłada wiadomości można zarezerwować tę wiadomość i zużywają go później.Rezerwacja wiadomości jest opisany bardziej szczegółowo w dalszej części tego tematu, w sekcji Rezerwacji wiadomość.

Biblioteki agentów włącza bloków komunikatów do asynchronicznego lub synchronicznie przekazywania wiadomości.Kiedy należy przekazać wiadomości do bloku komunikatów synchronicznie, na przykład za pomocą send funkcji, środowiska wykonawczego blokuje bieżącego kontekstu aż do bloku docelowego akceptuje lub odrzuca wiadomość.Kiedy należy przekazać wiadomości do bloku komunikatów asynchronicznie, na przykład za pomocą asend funkcji, środowiska wykonawczego oferuje wiadomość do obiektu docelowego, jeżeli obiekt docelowy zaakceptuje wiadomość, środowiska wykonawczego harmonogramów i asynchroniczny zadania, które propaguje wiadomości dla odbiorcy.Środowisko wykonawcze używa lekki zadań do propagowania wiadomości w sposób współpracy.Aby uzyskać więcej informacji na temat zadań lekki, zobacz Harmonogram zadań (współbieżność środowiska wykonawczego).

Aplikacje łączenia źródeł i cele do formularza sieciami wiadomości.Zazwyczaj łącze sieciowe i wywołanie send lub asend do przekazywania danych do sieci.Aby połączyć bloku komunikatów źródła do miejsca docelowego, wywołanie concurrency::ISource::link_target metody.Aby rozłączyć połączenie bloku źródłowego z obiektu docelowego, wywołanie concurrency::ISource::unlink_target metody.Aby rozłączyć bloku źródłowego wszystkie elementy docelowe, call concurrency::ISource::unlink_targets metody.Podczas jednego z typów bloku komunikatu wstępnie zdefiniowanych pozostawia lub ulega zniszczeniu, to automatycznie rozłącza się z bloków docelowej.Niektóre typy wiadomości bloku ograniczyć maksymalną liczbę obiektów docelowych, które mogą zapisywać dane w.Poniższej sekcji opisano ograniczenia, które stosuje się do wiadomości wstępnie zdefiniowanych typów bloku.

[U góry]

Omówienie typów bloku komunikatu

W poniższej tabeli opisano pokrótce rolę 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 odczytywane, wiele razy.

  • single_assignment
    Przechowuje jednej wiadomości, które mogą być zapisywane na jeden raz i odczytać z wiele razy.

  • Wywołanie
    Wykonuje pracę, gdy odbiera wiadomość.

  • Transformator
    Wykonuje pracę, gdy odbiera dane i wysyła wynik tej pracy do innego bloku docelowego.transformer Klasy może działać na różnych danych wejściowych i typy danych wyjściowych.

  • Wybór
    Wybiera pierwsze dostępne wiadomości z zestawu źródeł.

  • sprzężenie i Dołącz multitype
    Poczekaj, aż wszystkie wiadomości otrzymane od zestawu źródeł, a następnie połączyć wszystkie wiadomości w jednej wiadomości dla innego bloku komunikatów.

  • Czasomierz
    Wysyła wiadomość do bloku docelowego w regularnych interwałach.

Te typy bloku komunikatów mają różne charakterystyki, które były przydatne w różnych sytuacjach.Są pewne cechy charakterystyczne:

  • Typ rozprzestrzenianie: czy bloku komunikatów działa jako źródło danych i/lub odbiornika danych.

  • Porządkowanie wiadomości: czy bloku komunikatów utrzymuje oryginalnego zamówienia, w którym wiadomości są wysyłane lub odbierane.Każdy typ bloku komunikatu wstępnie zdefiniowanych utrzymuje oryginalnego zamówienia, w którym wysyła lub odbiera wiadomości.

  • Licznik źródła: Maksymalna liczba źródeł, które może odczytywać bloku komunikatów.

  • Docelowa liczba: Maksymalna liczba obiektów docelowych, które mogą zapisywać bloku komunikatów.

W poniższej tabeli przedstawiono, jak cechy te odnoszą się do różnych typów bloków komunikatów.

Typ bloku komunikatu

Typ rozprzestrzenianie (źródło, miejsce docelowe lub oba)

Wiadomość zamawiania (zamówione lub Unordered)

Licznik źródła

Licznik docelowego

unbounded_buffer

Oba

Zamówione

Bez ograniczeń

Bez ograniczeń

overwrite_buffer

Oba

Zamówione

Bez ograniczeń

Bez ograniczeń

single_assignment

Oba

Zamówione

Bez ograniczeń

Bez ograniczeń

call

Docelowy

Zamówione

Bez ograniczeń

Nie dotyczy

transformer

Oba

Zamówione

Bez ograniczeń

1

choice

Oba

Zamówione

10

1

join

Oba

Zamówione

Bez ograniczeń

1

multitype_join

Oba

Zamówione

10

1

timer

Źródło

Nie dotyczy

Nie dotyczy

1

W poniższych sekcjach opisano typy bloku komunikatów bardziej szczegółowo.

[U góry]

Klasa unbounded_buffer

Concurrency::unbounded_buffer klasy reprezentuje ogólnego przeznaczenia struktury obsługi wiadomości asynchronicznych.Ta klasa przechowuje kolejkę FIFO (first in first out) zawierająca wiadomości, do których może zapisywać wiele źródeł oraz z których może czytać wiele elementów docelowych.Kiedy element docelowy otrzyma wiadomość od unbounded_buffer obiektu, że wiadomość jest usuwana z kolejki wiadomości.W związku z tym chociaż unbounded_buffer obiekt może mieć wiele elementów docelowych, tylko jeden obiekt docelowy otrzymają każdej wiadomości.Klasa unbounded_buffer jest przydatna do przekazywania wielu wiadomości do innego składnika, gdy ten składnik musi otrzymać każdą wiadomość.

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 te z kopii 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:

  

Pełny przykład, który pokazuje, jak używać unbounded_buffer klasy, zobacz Porady: implementowanie różnych wzorców producent — konsument.

[U góry]

Klasa overwrite_buffer

Concurrency::overwrite_buffer podobny do klasy unbounded_buffer klasy, chyba że overwrite_buffer obiekt przechowuje tylko jednej wiadomości.Ponadto, kiedy element docelowy odbiera wiadomość z overwrite_buffer obiektu, że wiadomość nie jest usuwany z bufora.Dlatego wiele elementów docelowych otrzymuje kopię wiadomości.

overwrite_buffer Klasy jest przydatne, gdy chcesz przesłać wiele wiadomości do innego składnika, ale tylko ostatnia wartość musi tego składnika.Ta klasa jest też przydatna do rozgłaszania wiadomości to 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 object i następnie odczytuje bieżącą wartość z tego samego obiektu trzy razy.W tym przykładzie jest podobny do przykładu dla unbounded_buffer klasy.Jednakże overwrite_buffer klasa przechowuje tylko jednej wiadomości.Ponadto środowiska wykonawczego nie usuwa wiadomości z overwrite_buffer obiektu po jest odczytywana.

// 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:

  

Pełny przykład, który pokazuje, jak używać overwrite_buffer klasy, zobacz Porady: implementowanie różnych wzorców producent — konsument.

[U góry]

Klasa single_assignment

Concurrency::single_assignment podobny do klasy overwrite_buffer klasy, chyba że single_assignment obiektu mogą być zapisywane tylko jeden raz.Tak jak klasa overwrite_buffer, gdy element docelowy odbiera wiadomość od obiektu single_assignment, ta wiadomość nie jest usuwana z obiektu.Dlatego wiele elementów docelowych otrzymuje kopię wiadomości.single_assignment Klasy jest przydatne, gdy chcesz emitować jedną wiadomość 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 object i następnie odczytuje bieżącą wartość z tego samego obiektu trzy razy.W tym przykładzie jest podobny do przykładu dla overwrite_buffer klasy.Chociaż zarówno overwrite_buffer i single_assignment klas przechowywanie pojedynczej wiadomości, single_assignment klasy mogą być zapisywane tylko jeden 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:

  

Pełny przykład, który pokazuje, jak używać single_assignment klasy, zobacz Wskazówki: wdrażanie przyszłych operacji.

[U góry]

Klasa wywołania

Concurrency::call klasa działa jako odbiorca komunikatu, który wykonuje funkcje pracy po odebraniu danych.Ta funkcja pracy może być wyrażenie lambda, obiekt funkcji lub wskaźnika funkcji.A call obiektu zachowuje się inaczej niż wywołanie funkcji zwykłych, ponieważ działa równolegle z innymi składnikami, które wysyłają wiadomości do niej.Jeśli call obiekt wykonuje pracę po odebraniu wiadomości, dodaje tej wiadomości do kolejki.Każdy call procesy obiektu w kolejce wiadomości w kolejności, w jakiej są 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 odbierającym do konsoli.W przykładzie następnie wysyła trzy wartości do call obiektu.Ponieważ call obiektu przetwarza wiadomości w oddzielnym wątku, w tym przykładzie użyto również zmienną licznika i zdarzenia obiekt, aby zapewnić, że call obiektu przetwarza wszystkie wiadomości przed wmain , funkcja zwraca.

// 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:

  

Pełny przykład, który pokazuje, jak używać call klasy, zobacz Porady: zapewnianie funkcji pracy dla wywoływania oraz klasy transformatora.

[U góry]

Klasa transformatora

Concurrency::transformer klasa działa jako pewien odbiorca komunikatu, a nadawcy wiadomości.transformer Podobny do klasy call klasy, ponieważ spełnia on funkcję pracy użytkownika, po odebraniu danych.Jednakże transformer klasy wysyła również wynik funkcji pracy do obiektów odbiornika.Jak call obiektu, transformer obiekt działa równolegle z innymi składnikami, które wysyłają wiadomości do niej.Jeśli transformer obiekt wykonuje pracę po odebraniu wiadomości, dodaje tej wiadomości do kolejki.Każdy transformer obiektu przetwarza jego kolejce wiadomości w kolejności, w jakiej są odebrane.

transformer Klasy wysyła jego wiadomość do jednego celu.Jeśli ustawisz _PTarget parametru w Konstruktorze do NULL, później można określić lokalizację docelową, wywołując concurrency::link_target metody.

W odróżnieniu od wszystkich innych asynchronicznego bloku typy wiadomości, które są udostępniane przez biblioteki agentów transformer klasy może działać na różnych danych wejściowych i typy danych wyjściowych.Ta zdolność do transformacji danych z jednego typu do innego sprawia, że transformer klasy kluczowy element w wielu sieciach równoczesnych.Ponadto można dodać więcej funkcji równoległych 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 obiektu, że wejście wielokrotności każdego int wartość przez 0,33 aby wyprodukować double wartości jako dane wyjściowe.W przykładzie są następnie odbierane przekształconych wartości z tej samej transformer object 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:

  

Pełny przykład, który pokazuje, jak używać transformer klasy, zobacz Porady: używanie transformatora w potoku danych.

[U góry]

Klasa wyboru

Concurrency::choice klasy wybiera pierwsze dostępne wiadomości z zestawu źródeł.choice Klasy reprezentuje mechanizm przepływ sterowania zamiast mechanizm przepływ danych (temat Biblioteka agentów asynchronicznych w tym artykule opisano różnice między przepływ danych i przepływ sterowania).

Odczyt z obiektu wybór przypomina wywołanie funkcji interfejsu API systemu Windows WaitForMultipleObjects , gdy ma ona bWaitAll ustawiono parametr FALSE.Jednakże choice klasy wiąże się zamiast zdarzeń do obiektu zewnętrznego synchronizacji danych.

Zazwyczaj używana choice klasy wraz z concurrency::receive funkcji do kierowania przepływ sterowania w aplikacji.Użycie choice klasy, gdy masz do wyboru spośród buforów wiadomości, które mają różne typy.Użycie single_assignment klasy, gdy masz do wyboru spośród buforów wiadomości, które mają tego samego typu.

Kolejność, w której łączenie źródeł do choice obiektu jest ważne, ponieważ można określić, jaki komunikat jest zaznaczone.Na przykład, należy rozważyć przypadek gdzie połączyć kilka buforów wiadomości, które zawierają już wiadomość do choice obiektu.choice Obiektu wybiera wiadomości od pierwszego źródła połączonego z.Po dołączeniu wszystkich źródeł, choice obiektu zachowuje zamówienia, w którym każde źródło odbiera wiadomość.

Przykład

Poniższy przykład pokazuje podstawową strukturę jak pracować z choice klasy.W poniższym przykładzie użyto concurrency::make_choice funkcja służąca do tworzenia choice obiekt, który może wybierać spośród trzech bloków komunikatów.W przykładzie następnie oblicza różnych fibonacciego i zapisuje wynik każdego bloku różnych komunikatów.W przykładzie drukuje do konsoli następnie wiadomość, która opiera się na operację, która po raz pierwszy gotowy.

// 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:

     

Ponieważ zadanie, które oblicza 35th fibonacciego nie jest gwarantowana na zakończenie po raz pierwszy, dane wyjściowe tego przykładu mogą się różnić.

W poniższym przykładzie użyto concurrency::parallel_invoke algorytm obliczania fibonacciego równolegle.Aby uzyskać więcej informacji o parallel_invoke, zobacz Algorytmy równoległe.

Pełny przykład, który pokazuje, jak używać choice klasy, zobacz Porady: wybieranie spośród zadań wykonanych.

[U góry]

Klasy łączy oraz łączy typu multitype_join

Concurrency::join i concurrency::multitype_join klasy pozwalają oczekiwania dla każdego elementu członkowskiego zestawu źródeł do odbierania wiadomości.join Klasa działa na obiekty źródła, które mają wspólne typ komunikatu.multitype_join Klasa działa na obiekty źródeł, które mogą mieć różne rodzaje komunikatów.

Czytanie z join lub multitype_join obiektu przypomina wywołanie funkcji interfejsu API systemu Windows WaitForMultipleObjects , gdy ma ona bWaitAll ustawiono parametr TRUE.Jednak, podobnie jak choice obiektu, join i multitype_join obiekty za pomocą mechanizmu zdarzeń, która wiąże się zamiast zdarzeń do obiektu zewnętrznego synchronizacji danych.

Czytanie z join obiekt produkuje obiekt Vector obiektu.Czytanie z multitype_join obiekt produkuje 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ż zamówienia, w którym połączenia źródła bufory z join lub multitype_join obiekt jest skojarzony z kolejność elementów w wynikowym vector lub tuple obiektu, zaleca się nie odłączenie bufor istniejącego źródła z sprzężenia.Może to spowodować w zachowaniu nieokreślona.

Złączenia zachłanne vs. niezachłanne

join i multitype_join klasy wsparcie koncepcji sowa i sowa sprzężenia.A sowa sprzężenia akceptuje wiadomość z każdego z jej źródeł wiadomości staną się dostępne, dopóki wszystkie wiadomości nie są dostępne.A - sowa sprzężenia odbiera wiadomości w dwóch fazach.Po pierwsze-sowa sprzężenia czeka, aż oferowany jest wiadomość z każdego z jej źródeł.Po drugie po dostępne są wszystkie źródła wiadomości-sowa sprzężenia próbuje rezerwy te wiadomości.Jeśli ją zarezerwować każdej wiadomości, angażuje wszystkie wiadomości i propaguje je do swojego docelowego.W przeciwnym razie zwalnia, ani anulowanie rezerwacji wiadomości i ponownie czeka na komunikat o błędzie dla każdego źródła.

Intensywnie sprzężeń lepiej niż-sowa sprzężenia ponieważ one akceptować wiadomości natychmiast.Jednak w rzadkich przypadkach, intensywnie sprzężeń może prowadzić do zakleszczenia.Użyć sprzężenia sowa, gdy masz sprzężenia wielokrotne, które zawierają jeden lub więcej obiektów z udostępnianych źródeł.

Przykład

Poniższy przykład pokazuje podstawową strukturę jak pracować z join klasy.W poniższym przykładzie użyto concurrency::make_join funkcja służąca do tworzenia join obiekt, który odbiera z trzech single_assignment obiektów.Ten przykład oblicza różnych liczb Fibonacciego, przechowuje każdy wynik w innym single_assignment obiektu, a następnie drukuje do konsoli każdego doprowadzi to do join obiektu blokady.W tym przykładzie jest podobny do przykładu dla choice klasy, chyba że join klasy czeka, aż wszystkie źródła bloków komunikatów do odbierania wiadomości.

// 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:

  

W poniższym przykładzie użyto concurrency::parallel_invoke algorytm obliczania fibonacciego równolegle.Aby uzyskać więcej informacji o parallel_invoke, zobacz Algorytmy równoległe.

Kompletne przykłady przedstawiają metody korzystania join klasy, zobacz Porady: wybieranie spośród zadań wykonanych i Wskazówki: korzystanie ze złączy w celu zapobiegania zakleszczeniom.

[U góry]

Klasa czasomierza

Concurrency::timer klasa działa jako źródło wiadomości.A timer obiekt wysyła wiadomość do miejsca 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 przesłania do tylko jeden obiekt docelowy.Jeśli ustawisz _PTarget parametru w Konstruktorze do NULL, później można określić lokalizację docelową, wywołując concurrency::ISource::link_target metody.

A timer obiektu może być powtarzana lub niepowtarzającym.Aby utworzyć czasomierza powtarzanej, przekazać true dla _Repeating parametr podczas wywoływania konstruktora.W przeciwnym razie, pass false dla _Repeating parametr w celu utworzenia niepowtarzającym czasomierza.Jeśli zegar jest powtarzalna, wysyła tę samą widomość do swojego docelowego po upływie każdego interwału.

Tworzy bibliotekę agenci timer obiekty w Państwie-zaczął.Aby uruchomić obiektu timer, wywołanie concurrency::timer::start metody.Aby zatrzymać timer obiektów, zniszczyć obiektu lub wywołanie concurrency::timer::stop metody.Aby wstrzymać powtarzanej czasomierza, wywołanie 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 obiektów do raportowania postępu długotrwałą operacją.

// 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:

  

Pełny przykład, który pokazuje, jak używać timer klasy, zobacz Porady: wysyłanie komunikatu w regularnych odstępach czasu.

[U góry]

Filtrowanie komunikatów

Podczas tworzenia obiektu bloku komunikatu, można podać Funkcja filter Określa, czy blok wiadomości akceptuje lub odrzuca wiadomość.Funkcja filter jest przydatnym sposobem zagwarantowania, że bloku komunikatów otrzymuje tylko niektóre wartości.

Poniższy przykład pokazuje, jak utworzyć unbounded_buffer obiekt, który używa funkcji filtru do akceptowania wyłącznie liczby parzyste.unbounded_buffer Obiekt odrzuca numery nieparzyste i dlatego nie propaguje numery nieparzyste do bloków jego miejsce docelowe.

// 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:

  

Funkcja filter można funkcji lambda, wskaźnik funkcji lub obiekt funkcji.Każda funkcja Filtr przyjmuje jedną z następujących form.

  

Aby wyeliminować zbędne kopiowania danych, formularz drugi gdy masz typ agregatu, które propagowane przez wartość.

Obsługa filtrowania wiadomości Przepływ danych model programowania, w którym składniki wykonywanie obliczeń po otrzymaniu danych.Aby uzyskać przykłady, które umożliwiają sterowanie przepływem danych w sieci, przekazywania wiadomości funkcje filtrowania, zobacz Porady: korzystanie z filtra bloku komunikatów, Wskazówki: tworzenie agenta przepływu danych, i Wskazówki: tworzenie sieci przetwarzania obrazów.

[U góry]

Zastrzeżenie komunikatu

Komunikat rezerwacji umożliwia bloku komunikatów zarezerwować wiadomości w celu późniejszego użycia.Zazwyczaj rezerwacji wiadomości nie jest używany bezpośrednio.Jednak zrozumienia komunikatów rezerwacji może pomóc lepiej zrozumieć działanie niektórych typów bloku wstępnie zdefiniowanych wiadomości.

Należy wziąć pod uwagę-sowa i intensywnie sprzężenia.Rezerwacja wiadomości obu tych służy do rezerwowania wiadomości do późniejszego wykorzystania.Opisane wcześniej, łączyć intensywnie odbiera wiadomości w dwóch fazach.W pierwszej fazie, non chciwy join obiektu czeka na każdego z jej źródeł do odbierania wiadomości.Sowa sprzężenia próbuje następnie rezerwy te wiadomości.Jeśli ją zarezerwować każdej wiadomości, angażuje wszystkie wiadomości i propaguje je do swojego docelowego.W przeciwnym razie zwalnia, ani anulowanie rezerwacji wiadomości i ponownie czeka na komunikat o błędzie dla każdego źródła.

Intensywnie sprzężenia, który odczytuje komunikaty wejściowe z wielu źródeł, używa rezerwacji wiadomość do czytania wiadomości dodatkowe jednocześnie czeka na komunikat o błędzie z każdego źródła.Rozważmy na przykład łączyć sowa, który odbiera wiadomości z bloków komunikatów A i B.Jeśli sprzężenie sowa otrzymuje dwa komunikaty od B, ale jeszcze nie otrzymał wiadomość od A, intensywnie sprzężenia zapisuje identyfikator unikatowy wiadomości na drugi komunikat z B.Po intensywnie sprzężenia odbiera wiadomość z A i propaguje te wiadomości wykorzystuje identyfikator wiadomości zapisanych czy drugi komunikat z B jest nadal dostępny.

Podczas implementowania swój własny komunikat niestandardowy typ bloku, można użyć wiadomości rezerwacji.Na przykład o tym, jak utworzyć komunikat niestandardowy typ bloku, zobacz Wskazówki: tworzenie niestandardowego bloku komunikatów.

[U góry]

Zobacz też

Koncepcje

Biblioteka agentów asynchronicznych