Std::söz mü?
Düz ileri olan yeni standart kütüphane 15*, std::async
*std::future
bileşenleri (this answer bakın, örneğin, oldukça aşina değilim.
Ancak, ne işe yaradığını ve en iyi kullanılan std::promise
ne olduğunu kavramak mümkün değil. Sınıfının ötesinde bir sürü bilgi içeriyor kendisi değil standart belge sinopsis de just::thread yapar.
Birisi bir std::promise
ihtiyaç duyulan ve en deyimsel çözüm olduğu durumda, kısa, kısa ve öz bir örnek verebilir mi?
CEVAP
Durumu biraz daha iyi şimdi (hiç de küçük bir miktar cevaplara buradan çıkmalıyız!), anlıyorum biraz okumak benim de eklerim diye düşündüm.
C 11 ile ilgili olsa da, iki ayrı kavram vardır: zaman Uyumsuz bir hesaplama (başka bir yerde denilen bir fonksiyon), ve eş zamanlı yürütmeiplikiş yaptığı bir şey aynı anda). İkisi biraz dik kavramlardır. Zaman uyumsuz bir hesaplama iş parçacığı yürütme içeriği ise sadece fonksiyonellerine Ara farklı bir lezzet. Konuları kendi başlarına yararlı, ama pur&utangaç;bu tartışma poz için, bir uygulama ayrıntı onları tedavi edeceğim.
Zaman uyumsuz hesaplama için soyutlama bir hiyerarşi vardır. Örnek aşkına, bir argüman alır bir işlevi var varsayalım:
int foo(double, char, bool);
Öncelikle şablon var yazın gelecekteki değeri T
temsil std::future<T>
,. Value sonucu İçin Üye işlevi etkin bekle program eşitler ve utangaç olan get()
,; ıng ile alınabilir. Alternatif olarak, bir gelecek ya da sonucu zaten mevcut olup olmadığını yoklamak için kullanılabilecek wait_for()
destekler. Vadeli işlem zaman uyumsuz-damla düşünce re&; yer utangaç ve sıradan dönüş türleri için ment utangaç. Bizim örneğin fonksiyon std::future<int>
bekliyoruz.
Şimdi, bu hiyerarşide en yüksek en düşük seviye:
std::async
: en kullanışlı ve düz ileri bir şekilde gerçekleştirmek için bir zaman uyumsuz computaması)async
işlev şablonu döndüren, eşleşen gelecek hemen:auto fut = std::async(foo, 1.5, 'x', false); // is a std::future<int>
Ayrıntılar üzerinde çok az kontrole sahip. Özellikle, bile işlevi exe&utangaç olduğunu bilmiyoruz;cuaynı anda, seri olarak başka bir kara büyü
get()
üzerine ya da ted. Ancak, sonuç kolayca obgerektiğinde tainedauto res = fut.get(); // is an int
Şimdi nasıl kabul edebilirizuygulamak
async
, bir moda bu ama gibi bir şeybizkontrol. Örneğin, bu işlev ayrı bir konu yürütülecek ısrar edebiliriz. Biz zatenstd::thread
sınıfı yoluyla ayrı bir konu sağlayabilir.Soyutlama sonraki alt düzeyde tam olarak bunu yapıyor:
std::packaged_task
. Bu fonksiyon sarar ve işlevleri için bir gelecek değer, ama Aramümkün kendisi nesneyi döndürmek sağlayan bir şablondur ve arayan kullanıcı tarafından yapılabilir. Bu şekilde kurabiliriz:std::packaged_task<int(double, char, bool)> tsk(foo); auto fut = tsk.get_future(); // is a std::future<int>
Gelecek görev aradığımızda hazır hale gelir ve aramayı tamamlar. Bu bir se için ideal bir iştir ve pa utangaç&; oranı iplik utangaç. Biz sadece emin olmak içinhareket ettiriniş parçacığı görev:
std::thread thr(std::move(tsk), 1.5, 'x', false);
Konu hemen çalışmaya başlar. Biz de
detach
yajoin
sonunda kapsam veya zaman (örneğin kullanarak Anthony Williamsscoped_thread
sarıcı, dürüst olmalı standart kütüphane).std::thread
kullanarak ayrıntılarını bizi burada ilgilendirmiyor; sadece yathr
katılmak ayırmak için emin eninde sonunda olacak. Önemli olan işlev çağrısı bitirir zaman, sonuçlar hazır olduğunuauto res = fut.get(); // as before
Şimdi en alt seviyeye indik: Nasıl kiuygulamakpaketlenmiş görev? Bu
std::promise
giriyor. Söz bir gelecek ile iletişim kurmak için bir yapı taşıdır. Asıl adım buİş parçasıyla bir söz verir.
İş parçasıyla Sözü Bir Gelecek elde eder.
Söz, işlev bağımsız değişkenleri ile birlikte, ayrı bir iş parçacığı içine taşınır.
Yeni konu işlevini yürütür ve yerine getirir söz doldurur.
Özgün iş parçacığı sonuç alır.
Örnek olarak, burada bizim çok"": . paketlenmiş görevi kendi
template <typename> class my_task; template <typename R, typename ...Args> class my_task<R(Args...)> { std::function<R(Args...)> fn; std::promise<R> pr; // the promise of the result public: template <typename ...Ts> explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { } template <typename ...Ts> void operator()(Ts &&... ts) { pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise } std::future<R> get_future() { return pr.get_future(); } // disable copy, default move };
Bu şablon kullanımı aslında
std::packaged_task
ile aynı. Tüm görev dokunaklı söz, hareket araya toplayan unutmayın. Daha özel durumlarda, bir de hareket söz nesne açıkça içine yeni konu ve bir işlev bağımsız değişken iplik işlevi, ama bir görev paketi yukarıda görünüyor, daha esnek ve daha az zorlayıcı bir çözüm.
İstisnalar yapmak
Sözler istisnalar yakından ilişkilidir. Bir söz yalnız arayüzü özel durumlar söz üzerinde bir işlem mantıklı değil her durum onun durumu tamamen iletmek için yeterli değildir. Tüm özel durumları tür std::logic_error
dan türetilen std::future_error
. Öncelikle bazı kısıtlamalar açıklama:
Varsayılan yapılandırılmış bir söz etkin değil. Etkin olmayan sözler sonucu ölebilir.
Bir söz bir gelecek
get_future()
yoluyla elde olduğunda etkin hale gelir. Ancak, sadecebirgelecekte elde edilecek!Bir söz ya
set_value()
ile tatmin olmak ya da yaşam süresi sona ermeden önceset_exception()
ile özel bir set varsa onun geleceği tüketilecek ise gerekir. Memnun bir söz sonucu ölebilir, veget()
geleceği üzerinde kullanılabilir hale gelir. Bir istisna ile bir söz gelecekget()
çağrısı üzerine depolanan özel durum yükseltir. Eğer bu söz ne değeri, ne de dışında ölürse, gelecekget()
çağıran bir "söz" istisna. kırık arttıracak
İşte bu çeşitli istisnai davranışları göstermek için küçük bir test serisi. İlk olarak, koşum:
#include <iostream>
#include <future>
#include <exception>
#include <stdexcept>
int test();
int main()
{
try
{
return test();
}
catch (std::future_error const & e)
{
std::cout << "Future error: " << e.what() << " / " << e.code() << std::endl;
}
catch (std::exception const & e)
{
std::cout << "Standard exception: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown exception." << std::endl;
}
}
Şimdi testlere geçelim.
Durum 1: Etkin olmayan söz
int test()
{
std::promise<int> pr;
return 0;
}
// fine, no problems
Durum 2: Aktif söz, kullanılmayan
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
return 0;
}
// fine, no problems; fut.get() would block indefinitely
Durum 3: Çok fazla vadeli
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
auto fut2 = pr.get_future(); // Error: "Future already retrieved"
return 0;
}
Durum 4: Tatmin vaadi
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
}
return fut.get();
}
// Fine, returns "10".
Vaka 5: Çok fazla memnuniyet
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // Error: "Promise already satisfied"
}
return fut.get();
}
Aynı durum, eğer biri varsa atılıryaset_value
set_exception
.
Vaka 6: İstisna
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_exception(std::make_exception_ptr(std::runtime_error("Booboo")));
}
return fut.get();
}
// throws the runtime_error exception
Vaka 7: Kırık söz
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
} // Error: "broken promise"
return fut.get();
}