Bagikan melalui


Blok Pesan Asinkron

Pustaka Agen menyediakan beberapa jenis blok pesan yang memungkinkan Anda menyebarluaskan pesan di antara komponen aplikasi dengan cara yang aman untuk utas. Jenis blok pesan ini sering digunakan dengan berbagai rutinitas yang melewati pesan, seperti konkurensi::send, konkurensi::asend, konkurensi::receive, dan konkurensi::try_receive. Untuk informasi selengkapnya tentang rutinitas passing pesan yang ditentukan oleh Pustaka Agen, lihat Fungsi Passing Pesan.

Bagian

Topik ini berisi bagian berikut:

Sumber dan Target

Sumber dan target adalah dua peserta penting dalam passing pesan. Sumber mengacu pada titik akhir komunikasi yang mengirim pesan. Target mengacu pada titik akhir komunikasi yang menerima pesan. Anda dapat menganggap sumber sebagai titik akhir yang Anda baca dari dan target sebagai titik akhir yang Anda tulis. Aplikasi menghubungkan sumber dan target bersama-sama untuk membentuk jaringan olahpesan.

Pustaka Agen menggunakan dua kelas abstrak untuk mewakili sumber dan target: konkurensi::ISource dan konkurensi::ITarget. Jenis blok pesan yang bertindak sebagai sumber yang berasal dari ISource; jenis blok pesan yang bertindak sebagai target yang berasal dari ITarget. Jenis blok pesan yang bertindak sebagai sumber dan target yang berasal dari ISource dan ITarget.

[Atas]

Penyebaran Pesan

Penyebaran pesan adalah tindakan mengirim pesan dari satu komponen ke komponen lainnya. Saat blok pesan ditawarkan pesan, blok pesan dapat menerima, menolak, atau menunda pesan tersebut. Setiap jenis blok pesan menyimpan dan mengirimkan pesan dengan cara yang berbeda. Misalnya, unbounded_buffer kelas menyimpan jumlah pesan yang tidak terbatas, overwrite_buffer kelas menyimpan satu pesan sekaligus, dan kelas transformator menyimpan versi yang diubah dari setiap pesan. Jenis blok pesan ini dijelaskan secara lebih rinci nanti dalam dokumen ini.

Ketika blok pesan menerima pesan, blok pesan dapat secara opsional melakukan pekerjaan dan, jika blok pesan adalah sumber, teruskan pesan yang dihasilkan ke anggota jaringan lain. Blok pesan dapat menggunakan fungsi filter untuk menolak pesan yang tidak ingin diterimanya. Filter dijelaskan secara lebih rinci nanti dalam topik ini, di bagian Pemfilteran Pesan. Blok pesan yang menunda pesan dapat memesan pesan tersebut dan menggunakannya nanti. Reservasi pesan dijelaskan secara lebih rinci nanti dalam topik ini, di bagian Reservasi Pesan.

Pustaka Agen memungkinkan blok pesan untuk meneruskan pesan secara asinkron atau sinkron. Saat Anda meneruskan pesan ke blok pesan secara sinkron, misalnya, dengan menggunakan send fungsi , runtime memblokir konteks saat ini hingga blok target menerima atau menolak pesan. Saat Anda meneruskan pesan ke blok pesan secara asinkron, misalnya, dengan menggunakan asend fungsi , runtime menawarkan pesan ke target, dan jika target menerima pesan, runtime menjadwalkan tugas asinkron yang menyebarkan pesan ke penerima. Runtime menggunakan tugas ringan untuk menyebarluaskan pesan dengan cara yang kooperatif. Untuk informasi selengkapnya tentang tugas ringan, lihat Penjadwal Tugas.

Aplikasi menghubungkan sumber dan target bersama-sama untuk membentuk jaringan olahpesan. Biasanya, Anda menautkan jaringan dan memanggil send atau asend meneruskan data ke jaringan. Untuk menyambungkan blok pesan sumber ke target, panggil metode konkurensi::ISource::link_target . Untuk memutuskan sambungan blok sumber dari target, panggil metode konkurensi::ISource::unlink_target . Untuk memutuskan sambungan blok sumber dari semua targetnya, panggil metode konkurensi::ISource::unlink_targets . Ketika salah satu jenis blok pesan yang telah ditentukan sebelumnya meninggalkan cakupan atau dihancurkan, secara otomatis memutuskan koneksi dirinya dari blok target apa pun. Beberapa jenis blok pesan membatasi jumlah maksimum target yang dapat mereka tulis. Bagian berikut ini menjelaskan batasan yang berlaku untuk jenis blok pesan yang telah ditentukan sebelumnya.

[Atas]

Gambaran Umum Jenis Blok Pesan

Tabel berikut ini menjelaskan secara singkat peran jenis blok pesan penting.

unbounded_buffer
Menyimpan antrean pesan.

overwrite_buffer
Menyimpan satu pesan yang dapat ditulis ke dan dibaca dari beberapa kali.

single_assignment
Menyimpan satu pesan yang dapat ditulis ke satu kali dan membaca dari beberapa kali.

panggil
Melakukan pekerjaan saat menerima pesan.

Transformator
Melakukan pekerjaan saat menerima data dan mengirim hasil pekerjaan tersebut ke blok target lain. Kelas transformer dapat bertindak pada jenis input dan output yang berbeda.

pilihan
Memilih pesan pertama yang tersedia dari sekumpulan sumber.

gabungan dan gabungan multitipe
Tunggu hingga semua pesan diterima dari sekumpulan sumber lalu gabungkan pesan ke dalam satu pesan untuk blok pesan lain.

Timer
Mengirim pesan ke blok target secara berkala.

Jenis blok pesan ini memiliki karakteristik berbeda yang membuatnya berguna untuk situasi yang berbeda. Ini adalah beberapa karakteristik:

  • Jenis penyebaran: Apakah blok pesan bertindak sebagai sumber data, penerima data, atau keduanya.

  • Pengurutan pesan: Apakah blok pesan mempertahankan urutan asli di mana pesan dikirim atau diterima. Setiap jenis blok pesan yang telah ditentukan sebelumnya mempertahankan urutan asli di mana ia mengirim atau menerima pesan.

  • Jumlah sumber: Jumlah maksimum sumber yang dapat dibaca blok pesan.

  • Jumlah target: Jumlah maksimum target yang dapat ditulis blok pesan.

Tabel berikut ini memperlihatkan bagaimana karakteristik ini berhubungan dengan berbagai jenis blok pesan.

Jenis blok pesan Jenis penyebaran (Sumber, Target, atau Keduanya) Pengurutan pesan (Diurutkan atau Tidak Diurutkan) Jumlah sumber Jumlah target
unbounded_buffer Keduanya Dipesan Tanpa ikatan Tanpa ikatan
overwrite_buffer Keduanya Dipesan Tanpa ikatan Tanpa ikatan
single_assignment Keduanya Dipesan Tanpa ikatan Tanpa ikatan
call Target Dipesan Tanpa ikatan Tidak Berlaku
transformer Keduanya Dipesan Tanpa ikatan 1
choice Keduanya Dipesan 10 1
join Keduanya Dipesan Tanpa ikatan 1
multitype_join Keduanya Dipesan 10 1
timer Sumber Tidak Berlaku Tidak Berlaku 1

Bagian berikut ini menjelaskan jenis blok pesan secara lebih rinci.

[Atas]

Kelas unbounded_buffer

Kelas konkurensi::unbounded_buffer mewakili struktur olahpesan asinkron tujuan umum. Kelas ini menyimpan antrian pesan pertama, pertama (FIFO) yang dapat ditulis oleh berbagai sumber atau dibaca oleh beberapa target. Saat target menerima pesan dari unbounded_buffer objek, pesan tersebut dihapus dari antrean pesan. Oleh karena itu, meskipun unbounded_buffer objek dapat memiliki beberapa target, hanya satu target yang akan menerima setiap pesan. Kelas unbounded_buffer ini berguna ketika Anda ingin meneruskan beberapa pesan ke komponen lain, dan komponen tersebut harus menerima setiap pesan.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan unbounded_buffer kelas . Contoh ini mengirimkan tiga nilai ke unbounded_buffer objek lalu membaca kembali nilai tersebut dari objek yang sama.

// 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;
}

Contoh ini menghasilkan output berikut:

334455

Untuk contoh lengkap yang menunjukkan cara menggunakan unbounded_buffer kelas , lihat Cara: Menerapkan Berbagai Pola Produsen-Konsumen.

[Atas]

Kelas overwrite_buffer

Kelas konkurensi::overwrite_buffer menyerupan unbounded_buffer kelas, kecuali bahwa overwrite_buffer objek hanya menyimpan satu pesan. Selain itu, ketika target menerima pesan dari overwrite_buffer objek, pesan tersebut tidak dihapus dari buffer. Oleh karena itu, beberapa target menerima salinan pesan.

Kelas overwrite_buffer ini berguna ketika Anda ingin meneruskan beberapa pesan ke komponen lain, tetapi komponen tersebut hanya membutuhkan nilai terbaru. Kelas ini juga berguna saat Anda ingin menyiarkan pesan ke beberapa komponen.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan overwrite_buffer kelas . Contoh ini mengirimkan tiga nilai ke overwrite _buffer objek lalu membaca nilai saat ini dari objek yang sama tiga kali. Contoh ini mirip dengan contoh untuk unbounded_buffer kelas . Namun, overwrite_buffer kelas hanya menyimpan satu pesan. Selain itu, runtime tidak menghapus pesan dari overwrite_buffer objek setelah dibaca.

// 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;
}

Contoh ini menghasilkan output berikut:

555555

Untuk contoh lengkap yang menunjukkan cara menggunakan overwrite_buffer kelas , lihat Cara: Menerapkan Berbagai Pola Produsen-Konsumen.

[Atas]

Kelas single_assignment

Kelas konkurensi::single_assignment menyerupan overwrite_buffer kelas, kecuali bahwa single_assignment objek hanya dapat ditulis satu kali. Seperti kelas overwrite_buffer, ketika target menerima pesan dari objek single_assignment, pesan tersebut tidak dihapus dari objek tersebut. Oleh karena itu, beberapa target menerima salinan pesan. Kelas single_assignment ini berguna ketika Anda ingin menyiarkan satu pesan ke beberapa komponen.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan single_assignment kelas . Contoh ini mengirim tiga nilai ke single_assignment objek lalu membaca nilai saat ini dari objek yang sama tiga kali. Contoh ini mirip dengan contoh untuk overwrite_buffer kelas . Meskipun kelas overwrite_buffer dan single_assignment menyimpan satu pesan, single_assignment kelas hanya dapat ditulis untuk satu kali.

// 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;
}

Contoh ini menghasilkan output berikut:

333333

Untuk contoh lengkap yang menunjukkan cara menggunakan single_assignment kelas, lihat Panduan: Menerapkan Futures.

[Atas]

Kelas panggilan

Kelas konkurensi::panggilan bertindak sebagai penerima pesan yang melakukan fungsi kerja saat menerima data. Fungsi kerja ini dapat berupa ekspresi lambda, objek fungsi, atau penunjuk fungsi. Objek call berperilaku berbeda dari panggilan fungsi biasa karena bertindak secara paralel dengan komponen lain yang mengirim pesan ke dalamnya. call Jika objek melakukan pekerjaan saat menerima pesan, objek akan menambahkan pesan tersebut ke antrean. Setiap call objek memproses pesan antrean dalam urutan penerimaannya.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan call kelas . Contoh ini membuat call objek yang mencetak setiap nilai yang diterimanya ke konsol. Contoh kemudian mengirim tiga nilai ke call objek . call Karena objek memproses pesan pada utas terpisah, contoh ini juga menggunakan variabel penghitung dan objek peristiwa untuk memastikan bahwa call objek memproses semua pesan sebelum wmain fungsi kembali.

// 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();
}

Contoh ini menghasilkan output berikut:

334455

Untuk contoh lengkap yang menunjukkan cara menggunakan call kelas , lihat Cara: Menyediakan Fungsi Kerja ke Kelas panggilan dan transformator.

[Atas]

Kelas transformator

Kelas konkurensi::transformer bertindak sebagai penerima pesan dan sebagai pengirim pesan. Kelas transformer menyerupan call kelas karena melakukan fungsi kerja yang ditentukan pengguna saat menerima data. Namun, transformer kelas juga mengirimkan hasil fungsi kerja ke objek penerima. call Seperti objek, transformer objek bertindak secara paralel dengan komponen lain yang mengirim pesan ke objek tersebut. transformer Jika objek melakukan pekerjaan saat menerima pesan, objek akan menambahkan pesan tersebut ke antrean. Setiap transformer objek memproses pesan antreannya sesuai urutan penerimaannya.

Kelas transformer mengirimkan pesannya ke satu target. Jika Anda mengatur _PTarget parameter di konstruktor ke NULL, Anda nantinya dapat menentukan target dengan memanggil metode konkurensi::link_target .

Tidak seperti semua jenis blok pesan asinkron lainnya yang disediakan oleh Pustaka Agen, transformer kelas dapat bertindak pada jenis input dan output yang berbeda. Kemampuan untuk mengubah data dari satu jenis ke jenis lainnya membuat transformer kelas menjadi komponen utama di banyak jaringan bersamaan. Selain itu, Anda dapat menambahkan fungsionalitas paralel yang lebih halus dalam fungsi transformer kerja objek.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan transformer kelas . Contoh ini membuat transformer objek yang mengalikan setiap nilai input int sebesar 0,33 untuk menghasilkan double nilai sebagai output. Contoh kemudian menerima nilai yang diubah dari objek yang sama transformer dan mencetaknya ke konsol.

// 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;
}

Contoh ini menghasilkan output berikut:

10.8914.5218.15

Untuk contoh lengkap yang memperlihatkan cara menggunakan transformer kelas, lihat Cara: Menggunakan transformator dalam Alur Data.

[Atas]

kelas pilihan

Kelas konkurensi::choice memilih pesan pertama yang tersedia dari sekumpulan sumber. Kelas mewakili choice mekanisme aliran kontrol alih-alih mekanisme aliran data (topik Pustaka Agen Asinkron menjelaskan perbedaan antara aliran data dan aliran kontrol).

Membaca dari objek pilihan menyerupai panggilan fungsi WaitForMultipleObjects WINDOWS API ketika parameter diatur bWaitAll ke FALSE. Namun, choice kelas mengikat data ke peristiwa itu sendiri alih-alih ke objek sinkronisasi eksternal.

Biasanya, Anda menggunakan choice kelas bersama dengan fungsi konkurensi::receive untuk mendorong alur kontrol di aplikasi Anda. choice Gunakan kelas saat Anda harus memilih di antara buffer pesan yang memiliki jenis yang berbeda. single_assignment Gunakan kelas saat Anda harus memilih di antara buffer pesan yang memiliki jenis yang sama.

Urutan di mana Anda menautkan sumber ke choice objek penting karena dapat menentukan pesan mana yang dipilih. Misalnya, pertimbangkan kasus di mana Anda menautkan beberapa buffer pesan yang sudah berisi pesan ke choice objek. Objek choice memilih pesan dari sumber pertama yang ditautkan. Setelah Anda menautkan choice semua sumber, objek mempertahankan urutan di mana setiap sumber menerima pesan.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan choice kelas . Contoh ini menggunakan fungsi konkurensi::make_choice untuk membuat choice objek yang memilih di antara tiga blok pesan. Contohnya kemudian menghitung berbagai angka Fibonacci dan menyimpan masing-masing hasil dalam blok pesan yang berbeda. Contoh kemudian mencetak ke konsol pesan yang didasarkan pada operasi yang selesai terlebih dahulu.

// 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;
   }
}

Contoh ini menghasilkan contoh output berikut:

fib35 received its value first. Result = 9227465

Karena tugas yang menghitung angka Fibonacci ke-35 tidak dijamin selesai terlebih dahulu, output dari contoh ini dapat bervariasi.

Contoh ini menggunakan algoritma konkurensi::p arallel_invoke untuk menghitung angka Fibonacci secara paralel. Untuk informasi selengkapnya tentang parallel_invoke, lihat Algoritma Paralel.

Untuk contoh lengkap yang memperlihatkan cara menggunakan choice kelas, lihat Cara: Pilih Di Antara Tugas yang Selesai.

[Atas]

bergabung dan multitype_join Kelas

Kelas konkurensi::join dan concurrency::multitype_join memungkinkan Anda menunggu setiap anggota sekumpulan sumber menerima pesan. Kelas join bertindak pada objek sumber yang memiliki jenis pesan umum. Kelas multitype_join bertindak pada objek sumber yang dapat memiliki jenis pesan yang berbeda.

Membaca dari join objek atau multitype_join menyerupai panggilan fungsi WaitForMultipleObjects WINDOWS API ketika parameter diatur bWaitAll ke TRUE. Namun, sama seperti choice objek, join dan multitype_join objek menggunakan mekanisme peristiwa yang mengikat data ke peristiwa itu sendiri alih-alih ke objek sinkronisasi eksternal.

Membaca dari join objek menghasilkan objek std::vector . Membaca dari multitype_join objek menghasilkan objek std::tuple . Elemen muncul dalam objek ini dalam urutan yang sama dengan buffer sumber yang sesuai ditautkan ke join objek atau multitype_join . Karena urutan Anda menautkan buffer sumber ke join objek atau multitype_join dikaitkan dengan urutan elemen dalam objek atau tuple yang dihasilkanvector, kami sarankan Anda tidak membatalkan tautan buffer sumber yang ada dari gabungan. Melakukannya dapat mengakibatkan perilaku yang tidak ditentukan.

Gabungan Serakah Versus Non-Serakah

Kelas join dan multitype_join mendukung konsep gabungan serakah dan tidak serakah. Gabungan serakah menerima pesan dari setiap sumbernya saat pesan tersedia hingga semua pesan tersedia. Gabungan yang tidak serakah menerima pesan dalam dua fase. Pertama, gabungan yang tidak serakah menunggu sampai ditawarkan pesan dari masing-masing sumbernya. Kedua, setelah semua pesan sumber tersedia, gabungan yang tidak serakah mencoba memesan masing-masing pesan tersebut. Jika dapat memesan setiap pesan, pesan akan menggunakan semua pesan dan menyebarkannya ke targetnya. Jika tidak, ia merilis, atau membatalkan, reservasi pesan dan lagi menunggu setiap sumber menerima pesan.

Gabungan Serakah berkinerja lebih baik daripada gabungan yang tidak serakah karena mereka segera menerima pesan. Namun, dalam kasus yang jarang terjadi, gabungan serakah dapat menyebabkan kebuntuan. Gunakan gabungan yang tidak serakah saat Anda memiliki beberapa gabungan yang berisi satu atau beberapa objek sumber bersama.

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan join kelas . Contoh ini menggunakan fungsi konkurensi::make_join untuk membuat join objek yang menerima dari tiga single_assignment objek. Contoh ini menghitung berbagai angka Fibonacci, menyimpan setiap hasil dalam objek yang berbeda single_assignment , lalu mencetak ke konsol setiap hasil yang disimpan join objek. Contoh ini mirip dengan contoh untuk choice kelas, kecuali bahwa join kelas menunggu semua blok pesan sumber menerima pesan.

// 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;
}

Contoh ini menghasilkan output berikut:

fib35 = 9227465fib37 = 24157817half_of_fib42 = 1.33957e+008

Contoh ini menggunakan algoritma konkurensi::p arallel_invoke untuk menghitung angka Fibonacci secara paralel. Untuk informasi selengkapnya tentang parallel_invoke, lihat Algoritma Paralel.

Untuk contoh lengkap yang memperlihatkan cara menggunakan join kelas, lihat Cara: Memilih Di Antara Tugas dan Panduan yang Selesai: Menggunakan gabungan untuk Mencegah Kebuntuan.

[Atas]

Kelas timer

Kelas konkurensi::timer bertindak sebagai sumber pesan. Objek timer mengirim pesan ke target setelah periode waktu tertentu berlalu. Kelas timer ini berguna ketika Anda harus menunda pengiriman pesan atau Anda ingin mengirim pesan secara berkala.

Kelas timer mengirimkan pesannya hanya ke satu target. Jika Anda mengatur _PTarget parameter di konstruktor ke NULL, Anda nantinya dapat menentukan target dengan memanggil metode konkurensi::ISource::link_target .

Objek timer dapat berulang atau tidak berulang. Untuk membuat timer berulang, berikan true _Repeating parameter saat Anda memanggil konstruktor. Jika tidak, teruskan false _Repeating parameter untuk membuat timer yang tidak berulang. Jika timer berulang, timer akan mengirim pesan yang sama ke targetnya setelah setiap interval.

Pustaka Agen membuat timer objek dalam status tidak dimulai. Untuk memulai objek timer, panggil metode konkurensi::timer::start . Untuk menghentikan timer objek, hancurkan objek atau panggil metode konkurensi::timer::stop . Untuk menjeda timer berulang, panggil metode concurrency::timer::p ause .

Contoh

Contoh berikut menunjukkan struktur dasar cara bekerja dengan timer kelas . Contoh menggunakan timer objek dan call untuk melaporkan kemajuan operasi yang panjang.

// 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;
}

Contoh ini menghasilkan contoh output berikut:

Computing fib(42)..................................................result is 267914296

Untuk contoh lengkap yang menunjukkan cara menggunakan timer kelas, lihat Cara: Mengirim Pesan pada Interval Reguler.

[Atas]

Pemfilteran Pesan

Saat membuat objek blok pesan, Anda dapat menyediakan fungsi filter yang menentukan apakah blok pesan menerima atau menolak pesan. Fungsi filter adalah cara yang berguna untuk menjamin bahwa blok pesan hanya menerima nilai tertentu.

Contoh berikut menunjukkan cara membuat unbounded_buffer objek yang menggunakan fungsi filter untuk hanya menerima angka genap. Objek unbounded_buffer menolak angka ganjil, dan karenanya tidak menyebarkan angka ganjil ke blok targetnya.

// 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;
   }
}

Contoh ini menghasilkan output berikut:

0 2 4 6 8

Fungsi filter dapat berupa fungsi lambda, penunjuk fungsi, atau objek fungsi. Setiap fungsi filter mengambil salah satu formulir berikut.

bool (T)
bool (T const &)

Untuk menghilangkan penyalinan data yang tidak perlu, gunakan formulir kedua saat Anda memiliki jenis agregat yang disebarkan berdasarkan nilai.

Pemfilteran pesan mendukung model pemrograman aliran data, di mana komponen melakukan komputasi saat mereka menerima data. Untuk contoh yang menggunakan fungsi filter untuk mengontrol aliran data dalam jaringan yang melewati pesan, lihat Cara: Menggunakan Filter Blok Pesan, Panduan: Membuat Agen Aliran Data, dan Panduan: Membuat Jaringan Pemrosesan Gambar.

[Atas]

Reservasi Pesan

Reservasi pesan memungkinkan blok pesan untuk memesan pesan untuk digunakan nanti. Biasanya, reservasi pesan tidak digunakan secara langsung. Namun, memahami reservasi pesan dapat membantu Anda lebih memahami perilaku beberapa jenis blok pesan yang telah ditentukan sebelumnya.

Pertimbangkan gabungan yang tidak serakah dan serakah. Kedua hal ini menggunakan reservasi pesan untuk memesan pesan untuk digunakan nanti. Yang dijelaskan sebelumnya, gabungan yang tidak serakah menerima pesan dalam dua fase. Selama fase pertama, objek yang tidak serakah join menunggu setiap sumbernya menerima pesan. Gabungan yang tidak serakah kemudian mencoba untuk memesan masing-masing pesan tersebut. Jika dapat memesan setiap pesan, pesan akan menggunakan semua pesan dan menyebarkannya ke targetnya. Jika tidak, ia merilis, atau membatalkan, reservasi pesan dan lagi menunggu setiap sumber menerima pesan.

Gabungan serakah, yang juga membaca pesan input dari sejumlah sumber, menggunakan reservasi pesan untuk membaca pesan tambahan saat menunggu untuk menerima pesan dari setiap sumber. Misalnya, pertimbangkan gabungan serakah yang menerima pesan dari blok A pesan dan B. Jika gabungan serakah menerima dua pesan dari B tetapi belum menerima pesan dari A, gabungan serakah menyimpan pengidentifikasi pesan unik untuk pesan kedua dari B. Setelah gabungan serakah menerima pesan dari A dan menyebarluaskan pesan-pesan ini, ia menggunakan pengidentifikasi pesan tersimpan untuk melihat apakah pesan kedua dari B masih tersedia.

Anda dapat menggunakan reservasi pesan saat menerapkan jenis blok pesan kustom Anda sendiri. Untuk contoh tentang cara membuat jenis blok pesan kustom, lihat Panduan: Membuat Blok Pesan Kustom.

[Atas]

Lihat juga

Pustaka Agen Asinkron