2014-12-17 23 views
14

Farklı bir iş parçacığı üzerinde bir işlevi çağırmak ve sonucunu döndürmek için çok iş parçacıklı bir kod yazarak ve vaat/gelecek yazıyorum. simplicitly için, ben tamamen diş kısmını kaldırırız: Bu olmayan void döndüren bir işlev için çok çalışırBir (muhtemelen geçersiz) söz yerine getirin

template <typename F> 
auto blockingCall(F f) -> decltype(f()) 
{ 
    std::promise<decltype(f())> promise; 

    // fulfill the promise 
    promise.set_value(f()); 

    // block until we have a result 
    return promise.get_future().get(); 
} 

. Ve geleceği elde eden iade bildirimi de void için çalışır. Ama f bir void fonksiyonu, çünkü eğer sözünü edemez:

promise.set_value (f()); // hata: void ifadesi

geçersiz kullanımı sıralı void durumunda değeri ayarlayarak bazı akıllı yolu var mı, yoksa sadece bir aşırı yükleme yaparak sahip olduğunu call_set_value(promise, f) gibi bir yardımcı işlevi yazmak zorunda yapmak std::promise<R> ve std::promise<void> için?

+0

Kendim yapmak için şablon becerilerine sahip değilim, ancak dönüş türünde muhtemelen SFINAE olabileceğini hissettim. – Borgleader

+2

Arama tamamlanana kadar bekleyecekseniz, işlevi başka bir iş parçacığında çağırmanın amacı nedir? (Çağrıyı belirli bir * iş parçacığına göndermenin bariz durumunun engellenmesi.) – cdhowie

+4

Neden düşük düzey vaat kullanıyorsunuz - sadece std :: future kullanıyor olabilirsiniz –

cevap

11

A promise asenkron sonuç sağlayıcının tek türüdür Fonksiyon aşırı temiz bir çözümdür.

: yerine promise ait bir future (ve tabii ki void arasındaki fark olmayan boşluk sonuçları kolları) üzerinden kullanılabilir bir sonuç yapar çağırma dışında bir std::function benzer bir çağrılabilir nesneyi saran bir packaged_task kullanabilirsiniz
template <typename F> 
auto blockingCall(F f) -> decltype(f()) 
{ 
    std::packaged_task<decltype(f())()> task(std::move(f)); 

    task(); 

    // block until we have a result 
    return task.get_future().get(); 
} 

NB Mevcut standarda göre, bu kod, task() ve task.get_future() ayrı iş parçacıklarında (ve orijinalinizin bir söz vermesi) gerçekleşirse, bir veri yarışına sahip olacaktır, böylece görevi diğer iş parçacığına teslim etmeden önce get_future() numaralı telefonu aramalısınız. Pratikte, gerçek uygulamalarda güvenli olmalı ve zaten geçerli olması için bir kütüphane sorunu var (LWG 2412).

+0

Neden bir görevi bir "std :: function" öğesine taşıyamıyorum? Örneğin. std :: function func = [t = std :: taşı (görev)]() değiştirilemez {t(); }; '' '' noncopyable 'işlevi ile ilgili bir hata verir. – Barry

+1

'std :: function' devredilemez, bu nedenle hedef nesnesinin de kopyalanabilmesini gerektirir (hedefin türü silinir, bu nedenle' işlev ', yalnızca kopyalanabilir bir nesneyi sararken kopyalanamaz; çünkü hedef çalışma zamanında dinamik olarak değişebilir). 'packaged_task' sadece hareket eder, bu yüzden' '' işlevi' –

+0

Oh saklanamaz! Güzel. Bu çözümü beğendim. Ayrıca senin Spock birinden şapkasını değiştirdiğine sevindim, çünkü kesinlikle tek gözünüzü bile ürpertiyorsun :) – Barry

12

Evet. olarak,

set(promise, f); 

sonra aşırı fonksiyonları olarak set uygulamak:

template<typename F, typename R> 
void set(std::promise<R> & p, F && f) //handle non-void here 
{ 
    p.set_value(f()); 
} 

template<typename F> 
void set(std::promise<void> & p, F && f) //handle void here 
{ 
    f(); 
    p.set_value(); 
} 
İlgili konular