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]