Zaman Uyumsuz İleti Blokları
Aracılar Kitaplığı, iletileri uygulama bileşenleri arasında iş parçacığı güvenli bir şekilde yaymanızı sağlayan birkaç ileti bloğu türü sağlar. Bu ileti bloğu türleri genellikle eşzamanlılık::send, eşzamanlılık::asend, eşzamanlılık::alma ve eşzamanlılık::try_receive gibi çeşitli ileti geçirme yordamlarıyla birlikte kullanılır. Aracılar Kitaplığı tarafından tanımlanan ileti geçirme yordamları hakkında daha fazla bilgi için bkz . İleti Geçirme İşlevleri.
Bölümler
Bu konu, aşağıdaki bölümleri içerir:
Kaynaklar ve Hedefler
Kaynaklar ve hedefler, ileti geçirmede iki önemli katılımcıdır. Kaynak, ileti gönderen bir iletişim uç noktasına başvurur. Hedef, iletileri alan bir iletişim uç noktasına başvurur. Bir kaynağı, okuduğunuz bir uç nokta ve hedefi de yazdığınız bir uç nokta olarak düşünebilirsiniz. Uygulamalar, mesajlaşma ağları oluşturmak için kaynakları ve hedefleri birbirine bağlar.
Aracılar Kitaplığı, kaynakları ve hedefleri göstermek için iki soyut sınıf kullanır: eşzamanlılık::ISource ve eşzamanlılık::ITarget. Kaynak olarak davranan ileti bloğu türleri ; ISource
hedef olarak davranan ileti bloğu türleri adresinden ITarget
türetilir. Kaynak ve hedef olarak davranan ileti bloğu türleri hem hem ITarget
de ISource
'den türetilir.
[Üst]
İleti Yayma
İleti yayma , bir bileşenden diğerine ileti gönderme işlemidir. İleti bloğuna ileti sunulduğunda, bu iletiyi kabul edebilir, reddedebilir veya erteleyebilir. Her ileti bloğu türü iletileri farklı şekillerde depolar ve iletir. Örneğin, unbounded_buffer
sınıfı sınırsız sayıda ileti depolar, overwrite_buffer
sınıf bir kerede tek bir ileti depolar ve transformer sınıfı her iletinin değiştirilmiş bir sürümünü depolar. Bu ileti bloğu türleri, bu belgenin ilerleyen bölümlerinde daha ayrıntılı olarak açıklanmıştır.
İleti bloğu bir iletiyi kabul ettiğinde isteğe bağlı olarak iş gerçekleştirebilir ve ileti bloğu bir kaynaksa, sonuçta elde edilen iletiyi ağın başka bir üyesine geçirebilir. İleti bloğu, almak istemediği iletileri reddetmek için bir filtre işlevi kullanabilir. Filtreler, bu konunun devamında İleti Filtreleme bölümünde daha ayrıntılı olarak açıklanmıştır. Bir iletiyi erteleyen bir ileti bloğu, bu iletiyi ayırabilir ve daha sonra kullanabilir. İleti ayırma, bu konunun devamında İleti Ayırma bölümünde daha ayrıntılı olarak açıklanmıştır.
Aracılar Kitaplığı, ileti bloklarının iletileri zaman uyumsuz veya zaman uyumlu bir şekilde geçirmesini sağlar. örneğin işlevini kullanarak send
bir ileti bloğuna zaman uyumlu bir şekilde ileti geçirdiğinizde, hedef blok iletiyi kabul edene veya reddedene kadar çalışma zamanı geçerli bağlamı engeller. bir ileti bloğuna bir iletiyi zaman uyumsuz olarak geçirdiğinizde, örneğin işlevini kullanarak asend
çalışma zamanı iletiyi hedefe sunar ve hedef iletiyi kabul ederse, çalışma zamanı iletiyi alıcıya yayarak zaman uyumsuz bir görev zamanlar. Çalışma zamanı, iletileri işbirliğine dayalı bir şekilde yaymak için basit görevler kullanır. Basit görevler hakkında daha fazla bilgi için bkz . Görev Zamanlayıcı.
Uygulamalar, mesajlaşma ağları oluşturmak için kaynakları ve hedefleri birbirine bağlar. Genellikle, ağı bağlar ve ağa veri geçirmek için veya asend
çağrısında send
bulunursunuz. Kaynak ileti bloğunu hedefe bağlamak için eşzamanlılık::ISource::link_target yöntemini çağırın. Kaynak bloğun hedefle bağlantısını kesmek için eşzamanlılık::ISource::unlink_target yöntemini çağırın. Kaynak bloğun tüm hedeflerinin bağlantısını kesmek için eşzamanlılık::ISource::unlink_targets yöntemini çağırın. Önceden tanımlanmış ileti bloğu türlerinden biri kapsam dışına çıktığında veya yok edildiğinde, otomatik olarak tüm hedef bloklarla bağlantısını keser. Bazı ileti bloğu türleri, yazabilecekleri hedef sayısı üst sınırını kısıtlar. Aşağıdaki bölümde, önceden tanımlanmış ileti bloğu türleri için geçerli olan kısıtlamalar açıklanmaktadır.
[Üst]
İleti Bloğu Türlerine Genel Bakış
Aşağıdaki tabloda önemli ileti bloğu türlerinin rolü kısaca açıklanmaktadır.
Unbounded_buffer
bir ileti kuyruğu depolar.
overwrite_buffer
Birden çok kez yazılabilen ve okunabilen bir ileti depolar.
Single_assignment
Bir kereye yazılabilen ve birden çok kez okunabilen bir ileti depolar.
Çağrı
bir ileti aldığında çalışma gerçekleştirir.
Trafo
Veri aldığında ve bu çalışmanın sonucunu başka bir hedef bloğuna gönderdiğinde çalışma gerçekleştirir. transformer
sınıfı farklı giriş ve çıkış türleri üzerinde işlem yapabilir.
Seçim
Bir kaynak kümesinden kullanılabilir ilk iletiyi seçer.
join ve multitype join
Bir kaynak kümesinden tüm iletilerin alınmasını bekleyin ve ardından iletileri başka bir ileti bloğu için bir iletide birleştirin.
Zamanlayıcı
Düzenli aralıklarla hedef bloğa ileti gönderir.
Bu ileti bloğu türleri, farklı durumlarda yararlı olmalarını sağlayan farklı özelliklere sahiptir. Bazı özellikler şunlardır:
Yayma türü: İleti bloğunun veri kaynağı, veri alıcısı veya her ikisi gibi davranıp davranmadığı.
İleti sıralama: İleti bloğunun iletilerin gönderildiği veya alındığı özgün sırayı koruyup korumadığı. Önceden tanımlanmış her ileti bloğu türü, iletileri gönderdiği veya aldığı özgün sırayı korur.
Kaynak sayısı: İleti bloğunun okuyabileceği kaynak sayısı üst sınırı.
Hedef sayısı: İleti bloğunun yazabileceği hedef sayısı üst sınırı.
Aşağıdaki tabloda bu özelliklerin çeşitli ileti bloğu türleriyle ilişkisi gösterilmektedir.
İleti bloğu türü | Yayma türü (Kaynak, Hedef veya Her İkisi) | İleti sıralama (Sıralı veya Sıralanmamış) | Kaynak sayısı | Hedef sayısı |
---|---|---|---|---|
unbounded_buffer |
Her İkisi | Sipariş edilen | Sınırsız | Sınırsız |
overwrite_buffer |
Her İkisi | Sipariş edilen | Sınırsız | Sınırsız |
single_assignment |
Her İkisi | Sipariş edilen | Sınırsız | Sınırsız |
call |
Hedef | Sipariş edilen | Sınırsız | Geçerli değil |
transformer |
Her İkisi | Sipariş edilen | Sınırsız | Kategori 1 |
choice |
Her İkisi | Sipariş edilen | 10 | Kategori 1 |
join |
Her İkisi | Sipariş edilen | Sınırsız | Kategori 1 |
multitype_join |
Her İkisi | Sipariş edilen | 10 | Kategori 1 |
timer |
Source | Geçerli değil | Geçerli değil | Kategori 1 |
Aşağıdaki bölümlerde ileti bloğu türleri daha ayrıntılı olarak açıklanmaktadır.
[Üst]
unbounded_buffer Sınıfı
concurrency::unbounded_buffer sınıfı genel amaçlı zaman uyumsuz bir mesajlaşma yapısını temsil eder. Bu sınıf, iletilerin birden çok kaynak tarafından yazılabilen veya birden çok hedef tarafından okunabilen bir ilk giren ilk çıkar (FIFO) sırasını tutar. Hedef bir nesneden unbounded_buffer
ileti aldığında, bu ileti ileti kuyruğundan kaldırılır. Bu nedenle, bir unbounded_buffer
nesnenin birden çok hedefi olsa da, her iletiyi yalnızca bir hedef alır. unbounded_buffer
sınıfı, başka bir bileşene birden çok ileti geçirmek istediğinizde ve bu bileşenin her iletiyi alması gerektiğinde kullanışlıdır.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir unbounded_buffer
. Bu örnek bir unbounded_buffer
nesneye üç değer gönderir ve sonra bu değerleri aynı nesneden geri okur.
// 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;
}
Bu örnek aşağıdaki çıkışı oluşturur:
334455
Sınıfının nasıl kullanılacağını unbounded_buffer
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Çeşitli Üretici-Tüketici Desenlerini Uygulama.
[Üst]
overwrite_buffer Sınıfı
concurrency::overwrite_buffer sınıfı, bir nesnenin yalnızca bir overwrite_buffer
ileti depolaması dışında sınıfına unbounded_buffer
benzer. Ayrıca, hedef bir nesneden overwrite_buffer
bir ileti aldığında, bu ileti arabellekten kaldırılmaz. Bu nedenle, birden çok hedef iletinin bir kopyasını alır.
Sınıfı overwrite_buffer
, birden çok iletiyi başka bir bileşene geçirmek istediğinizde yararlıdır, ancak bu bileşen yalnızca en son değere ihtiyaç duyar. Bu sınıf, bir iletiyi birden çok bileşene yayınlamak istediğinizde de kullanışlıdır.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir overwrite_buffer
. Bu örnek bir overwrite _buffer
nesneye üç değer gönderir ve ardından aynı nesneden geçerli değeri üç kez okur. Bu örnek, sınıfın örneğine unbounded_buffer
benzer. Ancak, overwrite_buffer
sınıfı yalnızca bir ileti depolar. Ayrıca, çalışma zamanı okunduktan sonra bir overwrite_buffer
nesneden iletiyi kaldırmaz.
// 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;
}
Bu örnek aşağıdaki çıkışı oluşturur:
555555
Sınıfının nasıl kullanılacağını overwrite_buffer
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Çeşitli Üretici-Tüketici Desenlerini Uygulama.
[Üst]
single_assignment Sınıfı
concurrency::single_assignment sınıfı sınıfa overwrite_buffer
benzer, ancak bir nesne yalnızca bir single_assignment
kez yazılabilir. overwrite_buffer
sınıfı gibi, hedef de bir single_assignment
nesnesinden ileti aldığında, o ileti nesneden kaldırılmaz. Bu nedenle, birden çok hedef iletinin bir kopyasını alır. Sınıfı single_assignment
, bir iletiyi birden çok bileşene yayınlamak istediğinizde kullanışlıdır.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir single_assignment
. Bu örnek bir single_assignment
nesneye üç değer gönderir ve ardından aynı nesneden geçerli değeri üç kez okur. Bu örnek, sınıfın örneğine overwrite_buffer
benzer. Hem hem de overwrite_buffer
single_assignment
sınıfları tek bir ileti depolasa da, single_assignment
sınıf yalnızca bir kez yazılabilir.
// 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;
}
Bu örnek aşağıdaki çıkışı oluşturur:
333333
sınıfının nasıl kullanılacağını single_assignment
gösteren eksiksiz bir örnek için bkz . İzlenecek Yol: Vadeli İşlemleri Uygulama.
[Üst]
çağrı Sınıfı
concurrency::call sınıfı, veri aldığında bir iş işlevi gerçekleştiren bir ileti alıcısı gibi davranır. Bu iş işlevi bir lambda ifadesi, işlev nesnesi veya işlev işaretçisi olabilir. Nesne call
, sıradan bir işlev çağrısından farklı davranır çünkü ona ileti gönderen diğer bileşenlere paralel hareket eder. Bir call
nesne bir ileti aldığında iş gerçekleştiriyorsa, bu iletiyi kuyruğa ekler. Her call
nesne, kuyruğa alınan iletileri alındıkları sırayla işler.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir call
. Bu örnek, aldığı her değeri konsola yazdıran bir call
nesne oluşturur. Örnek daha sonra nesneye call
üç değer gönderir. call
Nesnesi iletileri ayrı bir iş parçacığında işlediğinden, bu örnekte nesnenin işlev döndürülmeden önce wmain
tüm iletileri işlediğinden call
emin olmak için bir sayaç değişkeni ve olay nesnesi de kullanılır.
// 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();
}
Bu örnek aşağıdaki çıkışı oluşturur:
334455
Sınıfın nasıl kullanılacağını call
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Çağrıya ve transformatör Sınıflarına İş İşlevleri Sağlama.
[Üst]
dönüştürücü Sınıfı
concurrency::transformer sınıfı hem ileti alıcısı hem de ileti gönderen olarak çalışır. sınıfa transformer
benzer call
çünkü veri aldığında kullanıcı tanımlı bir iş işlevi gerçekleştirir. Ancak sınıfı, transformer
iş işlevinin sonucunu alıcı nesnelere de gönderir. Nesne call
gibi, nesne transformer
de ona ileti gönderen diğer bileşenlere paralel olarak hareket eder. Bir transformer
nesne bir ileti aldığında iş gerçekleştiriyorsa, bu iletiyi kuyruğa ekler. Her transformer
nesne, kuyruğa alınan iletilerini alındıkları sırayla işler.
sınıfı iletisini transformer
tek bir hedefe gönderir. Oluşturucudaki parametresini _PTarget
olarak NULL
ayarlarsanız, daha sonra concurrency::link_target yöntemini çağırarak hedefi belirtebilirsiniz.
Aracılar Kitaplığı tarafından sağlanan diğer tüm zaman uyumsuz ileti bloğu türlerinden farklı olarak, transformer
sınıf farklı giriş ve çıkış türleri üzerinde işlem yapabilir. Bu türdeki verileri başka bir türe dönüştürme özelliği, sınıfı birçok eşzamanlı ağda önemli bir bileşen haline getirir transformer
. Buna ek olarak, bir transformer
nesnenin iş işlevine daha ayrıntılı paralel işlevsellik ekleyebilirsiniz.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir transformer
. Bu örnek, çıkış olarak bir transformer
değer üretmek için her giriş int
değerini 0,33'e katlayan bir double
nesne oluşturur. Örnek daha sonra dönüştürülen değerleri aynı transformer
nesneden alır ve konsola yazdırır.
// 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;
}
Bu örnek aşağıdaki çıkışı oluşturur:
10.8914.5218.15
Sınıfının nasıl kullanılacağını transformer
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Veri İşlem Hattında transformatör kullanma.
[Üst]
seçenek Sınıfı
concurrency::choice sınıfı, bir kaynak kümesinden kullanılabilir ilk iletiyi seçer. choice
sınıfı, veri akışı mekanizması yerine bir denetim akışı mekanizmasını temsil eder (Zaman Uyumsuz Aracılar Kitaplığı konusu, veri akışı ile denetim akışı arasındaki farkları açıklar).
Bir seçim nesnesinden okumak, parametresi olarak ayarlandığında Windows API işlevini WaitForMultipleObjects
çağırmaya bWaitAll
FALSE
benzer. Ancak, choice
sınıfı verileri bir dış eşitleme nesnesi yerine olayın kendisine bağlar.
Genellikle, uygulamanızda control-flow'ı yönlendirmek için concurrency::receive işleviyle birlikte sınıfını kullanırsınızchoice
. Farklı türlerde choice
ileti arabellekleri arasından seçim yapmak zorunda olduğunuzda sınıfını kullanın. Aynı türe single_assignment
sahip ileti arabellekleri arasından seçim yapmak zorunda olduğunuzda sınıfını kullanın.
Hangi iletinin seçildiğini belirleyebildiğinden, kaynakları bir choice
nesneye bağlama sırası önemlidir. Örneğin, zaten bir ileti içeren birden çok ileti arabelleğini bir choice
nesneye bağladığınız durumu göz önünde bulundurun. Nesnesi, choice
bağlı olduğu ilk kaynaktan iletiyi seçer. Tüm kaynakları bağladıktan sonra nesne, choice
her kaynağın ileti alma sırasını korur.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir choice
. Bu örnekte eşzamanlılık::make_choice işlevi, üç ileti bloğu arasından seçim yapılan bir choice
nesne oluşturmak için kullanılır. Örnek daha sonra çeşitli Fibonacci numaralarını hesaplar ve her sonucu farklı bir ileti bloğunda depolar. Örnek daha sonra konsola ilk tamamlanan işlemi temel alan bir ileti yazdırır.
// 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;
}
}
Bu örnek aşağıdaki örnek çıkışı oluşturur:
fib35 received its value first. Result = 9227465
35. Fibonacci sayısını hesaplayan görevin önce bitmesi garanti edilmediğinden, bu örneğin çıktısı farklılık gösterebilir.
Bu örnek, Fibonacci sayılarını paralel olarak hesaplamak için concurrency::p arallel_invoke algoritmasını kullanır. hakkında parallel_invoke
daha fazla bilgi için bkz. Paralel Algoritmalar.
Sınıfın nasıl kullanılacağını choice
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Tamamlanan Görevler Arasından Seçim Yapma.
[Üst]
join ve multitype_join Sınıfları
Eşzamanlılık::join ve concurrency::multitype_join sınıfları, bir kaynak kümesinin her üyesinin ileti almasını beklemenize olanak sağlar. sınıfı, join
ortak ileti türüne sahip kaynak nesneler üzerinde hareket eder. sınıfı, multitype_join
farklı ileti türlerine sahip olabilecek kaynak nesneler üzerinde hareket eder.
Bir join
veya multitype_join
nesnesinden okumak, parametresi olarak ayarlandığında Windows API işlevini WaitForMultipleObjects
çağırmaya bWaitAll
TRUE
benzer. Ancak, tıpkı bir choice
nesne gibi ve multitype_join
nesneler de join
verileri dış eşitleme nesnesi yerine olayın kendisine bağlayan bir olay mekanizması kullanır.
Nesneden join
okuma bir std::vector nesnesi oluşturur. Nesneden multitype_join
okuma bir std::tuple nesnesi oluşturur. Öğeler bu nesnelerde karşılık gelen kaynak arabelleklerinin veya multitype_join
nesnesine join
bağlandıkları sırada görünür. Kaynak arabellekleri bir join
veya multitype_join
nesnesine bağladığınız sıra, sonuçta elde vector
edilen veya tuple
nesnedeki öğelerin sırasıyla ilişkilendirildiğinden, var olan bir kaynak arabelleğin birleştirmeyle bağlantısını kaldırmamanızı öneririz. Bunun yapılması, belirtilmeyen davranışlara neden olabilir.
Doyumsuz Olmayan Birleştirmelere Karşı Doyumsuz
join
ve multitype_join
sınıfları doyumsuz ve doyumsuz olmayan birleşimler kavramını destekler. Doyumsuz birleştirme, tüm iletiler kullanılabilir olana kadar iletiler kullanılabilir hale geldikçe her kaynaktan bir ileti kabul eder. Doyumsuz olmayan birleştirme, iletileri iki aşamada alır. İlk olarak, doyumsuz olmayan bir birleştirme, her kaynaktan bir ileti sunulana kadar bekler. İkincisi, tüm kaynak iletiler kullanılabilir olduktan sonra doyumsuz olmayan bir birleştirme bu iletilerin her birini ayırmaya çalışır. Her iletiyi ayırabiliyorsa, tüm iletileri tüketir ve hedefine yar. Aksi takdirde, ileti rezervasyonları yayımlar veya iptal eder ve her kaynağın bir ileti almasını tekrar bekler.
Doyumsuz birleşimler, iletileri hemen kabul ettikleri için doyumsuz olmayan birleştirmelerden daha iyi performans gösterir. Ancak, nadir durumlarda, doyumsuz birleşimler kilitlenmelere yol açabilir. Bir veya daha fazla paylaşılan kaynak nesne içeren birden çok birleştirmeniz olduğunda doyumsuz olmayan bir birleşim kullanın.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir join
. Bu örnek, üç single_assignment
nesneden alan bir join
nesne oluşturmak için eşzamanlılık::make_join işlevini kullanır. Bu örnek çeşitli Fibonacci sayılarını hesaplar, her sonucu farklı single_assignment
bir nesnede depolar ve ardından nesnenin barındırmış olduğu her sonucu konsola join
yazdırır. Bu örnek, sınıfın örneğine choice
benzer, ancak sınıfın join
tüm kaynak ileti bloklarının bir ileti almasını beklemesi dışında.
// 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;
}
Bu örnek aşağıdaki çıkışı oluşturur:
fib35 = 9227465fib37 = 24157817half_of_fib42 = 1.33957e+008
Bu örnek, Fibonacci sayılarını paralel olarak hesaplamak için concurrency::p arallel_invoke algoritmasını kullanır. hakkında parallel_invoke
daha fazla bilgi için bkz. Paralel Algoritmalar.
Sınıfın nasıl kullanılacağını join
gösteren eksiksiz örnekler için bkz . Nasıl yapılır: Tamamlanan Görevler Arasında Seçim Yapma ve İzlenecek Yol: Kilitlenmeyi Önlemek için Birleştirmeyi Kullanma.
[Üst]
süreölçer Sınıfı
concurrency::timer sınıfı bir ileti kaynağı işlevi görür. Bir timer
nesne, belirtilen süre dolduktan sonra hedefe bir ileti gönderir. Sınıf timer
, ileti göndermeyi geciktirmeniz gerektiğinde veya düzenli aralıklarla ileti göndermek istediğinizde kullanışlıdır.
sınıfı iletisini timer
tek bir hedefe gönderir. Oluşturucudaki parametresini _PTarget
olarak NULL
ayarlarsanız, daha sonra eşzamanlılık::ISource::link_target yöntemini çağırarak hedefi belirtebilirsiniz.
Bir timer
nesne yineleniyor veya yinelenemiyor olabilir. Yinelenen bir zamanlayıcı oluşturmak için oluşturucuyu _Repeating
çağırdığınızda parametresini geçirintrue
. Aksi takdirde, yinelenmeyen _Repeating
bir süreölçer oluşturmak için parametresini geçirinfalse
. Zamanlayıcı yineleniyorsa, her aralık sonrasında hedefine aynı iletiyi gönderir.
Aracılar Kitaplığı, başlatılmamış durumda nesneler oluşturur timer
. Zamanlayıcı nesnesini başlatmak için concurrency::timer::start yöntemini çağırın. Bir timer
nesneyi durdurmak için nesneyi yok edin veya concurrency::timer::stop yöntemini çağırın. Yinelenen zamanlayıcıyı duraklatmak için concurrency::timer::p ause yöntemini çağırın.
Örnek
Aşağıdaki örnekte, sınıfıyla çalışmanın temel yapısı gösterilmektedir timer
. Örnek, uzun bir işlemin ilerleme durumunu raporlamak için ve call
nesnelerini kullanırtimer
.
// 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;
}
Bu örnek aşağıdaki örnek çıkışı oluşturur:
Computing fib(42)..................................................result is 267914296
Sınıfın nasıl kullanılacağını timer
gösteren eksiksiz bir örnek için bkz . Nasıl yapılır: Düzenli Aralıklarla İleti Gönderme.
[Üst]
İleti Filtreleme
İleti bloğu nesnesi oluşturduğunuzda, ileti bloğunun bir iletiyi kabul edip etmediğini belirleyen bir filtre işlevi sağlayabilirsiniz. Filtre işlevi, ileti bloğunun yalnızca belirli değerleri almasını garanti etmenin kullanışlı bir yoludur.
Aşağıdaki örnekte, yalnızca çift sayıları kabul etmek için filtre işlevi kullanan bir nesnenin nasıl oluşturulacağı unbounded_buffer
gösterilmektedir. Nesnesi unbounded_buffer
tek sayıları reddeder ve bu nedenle tek sayıları hedef bloklarına yaymıyor.
// 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;
}
}
Bu örnek aşağıdaki çıkışı oluşturur:
0 2 4 6 8
Filtre işlevi bir lambda işlevi, işlev işaretçisi veya işlev nesnesi olabilir. Her filtre işlevi aşağıdaki formlardan birini alır.
bool (T)
bool (T const &)
Gereksiz veri kopyalamayı ortadan kaldırmak için, değere göre yayılan bir toplama türünüz olduğunda ikinci formu kullanın.
İleti filtreleme, bileşenlerin veri aldığında hesaplamalar gerçekleştirdiği veri akışı programlama modelini destekler. İletiden geçen ağdaki veri akışını denetlemek için filtre işlevlerini kullanan örnekler için bkz . Nasıl yapılır: İleti Bloğu Filtresi Kullanma, İzlenecek Yol: Veri Akışı Aracısı Oluşturma ve İzlenecek Yol: Görüntü İşleme Ağı Oluşturma.
[Üst]
İleti Rezervasyonu
İleti ayırma , ileti bloğunun bir iletiyi daha sonra kullanmak üzere ayırmasını sağlar. Genellikle ileti ayırma doğrudan kullanılmaz. Ancak, ileti ayırmayı anlamak, önceden tanımlanmış ileti bloğu türlerinden bazılarının davranışını daha iyi anlamanıza yardımcı olabilir.
Doyumsuz olmayan ve açgözlü birleşimleri göz önünde bulundurun. Bunların her ikisi de iletileri daha sonra kullanmak üzere ayırmak için ileti ayırmayı kullanır. Daha önce açıklanan bir doyumsuz olmayan birleştirme, iletileri iki aşamada alır. İlk aşamada doyumsuz join
olmayan bir nesne, kaynaklarının her birinin ileti almasını bekler. Doyumsuz olmayan bir birleştirme daha sonra bu iletilerin her birini ayırmaya çalışır. Her iletiyi ayırabiliyorsa, tüm iletileri tüketir ve hedefine yar. Aksi takdirde, ileti rezervasyonları yayımlar veya iptal eder ve her kaynağın bir ileti almasını tekrar bekler.
Bir dizi kaynaktan gelen giriş iletilerini de okuyan doyumsuz birleştirme, her kaynaktan bir ileti almayı beklerken ek iletileri okumak için ileti ayırmayı kullanır. Örneğin, ve B
ileti bloklarından A
ileti alan doyumsuz bir birleştirme düşünün. Doyumsuz birleşim B'den iki ileti alır, ancak henüz 'den A
bir ileti almadıysa, doyumsuz birleştirme, 'den B
ikinci ileti için benzersiz ileti tanımlayıcısını kaydeder. Doyumsuz birleştirmeden A
bir ileti aldıktan ve bu iletileri yaydıktan sonra, ikinci iletinin hala kullanılabilir olup olmadığını görmek için kaydedilen ileti B
tanımlayıcısını kullanır.
Kendi özel ileti bloğu türlerinizi uygularken ileti ayırmayı kullanabilirsiniz. Özel ileti bloğu türü oluşturma hakkında bir örnek için bkz . İzlenecek Yol: Özel İleti Bloğu Oluşturma.
[Üst]
Ayrıca bkz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin