Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Perpustakaan Agen menyediakan beberapa jenis blok pesan yang memungkinkan Anda menyebarluaskan pesan di antara komponen aplikasi secara aman terhadap utas. Jenis blok pesan ini sering digunakan dengan berbagai rutinitas pengiriman pesan, seperti concurrency::send, concurrency::asend, concurrency::receive, dan concurrency::try_receive. Untuk informasi selengkapnya tentang fungsi pemrosesan pesan yang ditentukan oleh Pustaka Agen, lihat Fungsi Pemrosesan 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, ia 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 Message Reservation.
Perpustakaan Agen memungkinkan blok pesan meneruskan pesan baik secara asinkron maupun 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 concurrency::ISource::unlink_target. Untuk memutuskan sambungan blok sumber dari semua target miliknya, panggil metode concurrency::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.
penugasan_tunggal
Menyimpan satu pesan yang dapat ditulis sekali dan dibaca berkali-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 sasaran: Jumlah maksimum sasaran yang dapat ditulis oleh 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 |
Sasaran | 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 masuk pertama, keluar pertama (FIFO) dari pesan yang dapat ditulis oleh berbagai sumber atau dibaca oleh banyak 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 kelas unbounded_buffer. 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 kelas unbounded_buffer, lihat Cara: Menerapkan Berbagai Pola Produsen-Konsumen.
[Atas]
Kelas overwrite_buffer
Kelas konkurensi::overwrite_buffer menyerupai kelas unbounded_buffer, kecuali bahwa objek overwrite_buffer 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 kelas overwrite_buffer. 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 kelas overwrite_buffer, lihat Cara: Menerapkan Berbagai Pola Produsen-Konsumen.
[Atas]
Kelas single_assignment
Kelas konkurensi::single_assignment menyerupai kelas overwrite_buffer, kecuali bahwa objek single_assignment hanya dapat ditulis satu kali saja. 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 kelas single_assignment. 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]
Pemanggilan Kelas
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 sebuah objek sedang melakukan pekerjaan saat menerima pesan, maka objek tersebut akan menambahkan pesan tersebut ke dalam antrean. Setiap call objek memproses pesan antrean dalam urutan penerimaannya.
Contoh
Contoh berikut menunjukkan struktur dasar cara bekerja dengan kelas call. Contoh ini membuat call objek yang mencetak setiap nilai yang diterimanya ke konsol. Contoh kemudian mengirim tiga nilai ke call objek . Karena call objek memproses pesan pada utas terpisah, contoh ini juga menggunakan variabel penghitung dan objek event untuk memastikan bahwa call objek memproses semua pesan sebelum fungsi wmain mengembalikan.
// 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 kelas call, 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 kelas juga mengirimkan hasil fungsi kerja ke objek penerima. Seperti objek call, objek transformer bekerja secara paralel dengan komponen lain yang mengirim pesan kepadanya. Jika sebuah objek sedang melakukan pekerjaan saat menerima pesan, objek tersebut akan menambahkan pesan ke dalam 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 berbutir halus dalam fungsi kerja dari objek transformer.
Contoh
Contoh berikut menunjukkan struktur dasar cara bekerja dengan kelas transformer. 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 kelas transformer, lihat Cara: Menggunakan transformator dalam Pipa Data.
[Atas]
kelas pilihan
Kelas konkurensi::choice memilih pesan pertama yang tersedia dari sekumpulan sumber. Kelas choice mewakili mekanisme aliran kontrol alih-alih mekanisme aliran data (topik Perpustakaan Agen Asinkron menggambarkan 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 bersama dengan fungsi concurrency::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 kelas choice. 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 pesan ke konsol berdasarkan 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 concurrency::parallel_invoke untuk menghitung bilangan Fibonacci secara paralel. Untuk informasi selengkapnya tentang parallel_invoke, lihat Algoritma Paralel.
Untuk contoh lengkap yang memperlihatkan cara menggunakan kelas choice, lihat Cara: Memilih Di Antara Tugas yang Telah 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 objek join atau multitype_join menyerupai pemanggilan fungsi Windows API WaitForMultipleObjects ketika parameter bWaitAll diatur 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 . Objek multitype_join ketika dibaca menghasilkan sebuah objek std::tuple. Elemen muncul dalam objek ini dalam urutan yang sama dengan buffer sumber yang sesuai, yang ditautkan ke objek join atau multitype_join. Karena urutan Anda menautkan buffer sumber ke objek join atau multitype_join dikaitkan dengan urutan elemen dalam objek vector atau tuple yang dihasilkan, kami sarankan Anda tidak membatalkan tautan buffer sumber yang ada dari suatu penggabungan. Melakukannya dapat mengakibatkan perilaku yang tidak ditentukan.
Gabungan Serakah Versus Non-Serakah
Kelas join dan multitype_join mendukung konsep penggabungan rakus dan tidak rakus. Gabungan serakah menerima pesan dari setiap sumbernya ketika pesan tersedia hingga semua pesan terkumpul. Gabungan non-greedy menerima pesan dalam dua tahap. Pertama, gabungan yang tidak rakus menunggu sampai diberikan pesan dari setiap sumbernya. Kedua, setelah semua pesan sumber tersedia, gabungan yang tidak serakah mencoba memesan masing-masing pesan tersebut. Jika dapat menyimpan setiap pesan, ia mengkonsumsi semua pesan dan menyalurkannya ke targetnya. Jika tidak, ia merilis atau membatalkan reservasi pesan dan kembali menunggu setiap sumber untuk menerima pesan.
Gabungan yang rakus berkinerja lebih baik daripada gabungan yang tidak rakus 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 kelas join. Contoh ini menggunakan fungsi concurrency::make_join untuk membuat objek join yang menerima data dari tiga objek single_assignment. 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 concurrency::parallel_invoke untuk menghitung angka Fibonacci secara paralel. Untuk informasi selengkapnya tentang parallel_invoke, lihat Algoritma Paralel.
Untuk contoh lengkap yang memperlihatkan cara menggunakan kelas join, lihat Cara: Memilih Di Antara Tugas yang Telah Selesai dan Panduan: Menggunakan 'join' 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 sebagai parameter _Repeating saat Anda memanggil konstruktor. Jika tidak, operasikan false ke parameter _Repeating untuk membuat timer yang tidak berulang. Jika timer berulang, timer akan mengirim pesan yang sama ke targetnya setelah setiap interval.
Pustaka Agen membuat objek timer dalam keadaan belum dimulai. Untuk memulai objek timer, panggil metode konkurensi::timer::start . Untuk menghentikan timer objek, menghancurkan objek tersebut atau panggil metode concurrency::timer::stop. Untuk menjeda timer berulang, panggil concurrency::timer::pause metode.
Contoh
Contoh berikut menunjukkan struktur dasar cara bekerja dengan kelas timer. Contoh menggunakan objek timer 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 kelas timer, 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 pemindahan 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 di kemudian waktu. 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 non-greedy dan greedy. 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 menyimpan setiap pesan, ia mengkonsumsi semua pesan dan menyalurkannya ke targetnya. Jika tidak, ia merilis atau membatalkan reservasi pesan dan kembali menunggu setiap sumber untuk menerima pesan.
Gabungan rakus, yang juga membaca pesan input dari sejumlah sumber, menggunakan mekanisme pemesanan pesan untuk membaca pesan tambahan saat menunggu menerima pesan dari setiap sumber. Misalnya, pertimbangkan "greedy join" yang menerima pesan dari blok pesan A 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]