2017-03-01 30 views
5

Czy to bezpieczne, jak w przypadku std::mutex, aby std::promise<T> miało być wykonane mutable, czy to zależy od T? Jak w:Czy std :: obiecuje <T> wątek bezpieczny?

using Data = std::tuple<bool, int, int>; 

struct X { 

    std::future<Data> prepare() const { 
     return m_promise.get_future(); 
    } 

    void asyncHandler(int a, int b) const { 
     m_promise.set_value({true, a, b}); 
    } 

    void cancel() const { 
     m_promise.set_value({false, 0, 0}); 
    } 

    mutable std::promise<Data> m_promise; // Is this safe? 
}; 


void performAsyncOp(const X& x) { 
    std::future<Data> fut = x.prepare(); 
    dispatch(x); 
    std::future_status result = fut.wait_for(std::chrono::milliseconds(150)); 
    if (result == std::future_status::timeout) { 
     x.cancel(); 
    } 

    handleResult(fut.get()); 
} 
+0

Okazuje się, że ten wzorzec jest zepsuty, ponieważ nie można zresetować kontraktów terminowych. Pomyślałem, że future.get() zresetowałby go, ale tak nie jest. Staram się naprawdę zrozumieć wszystkie te obietnice/przyszłe sprawy. – James

Odpowiedz

4

Rzućmy szczegółowe spojrzenie na API:

// retrieving the result 
future<R> get_future(); 

// setting the result 
void set_value(see below); 
void set_exception(exception_ptr p); 

// setting the result with deferred notification 
void set_value_at_thread_exit(see below); 
void set_exception_at_thread_exit(exception_ptr p); 

Żadna z metod jest oznaczony const, więc nie możemy wywnioskować żadnej wiedzy o constness od właśnie tego. Standard wymusza jednak bezpieczeństwo wątków na następujących metodach: (c.f. 33.6.6.2): set_­value, , set_­value_­at_­thread_­exit i set_­exception_­at_­thread_­exit.

Pozostawia to get_future nieokreśloną w odniesieniu do bezpieczeństwa gwintu. Jednak get_future zgłasza wyjątek, jeśli jest wywoływany więcej niż raz, c.f. 33.6.6.14.1. Wywoływanie get_future z wielu wątków nie ma sensu z praktycznego punktu widzenia.

Nie ma gwarancji na bezpieczeństwo wątków podczas wywoływania get_future i dowolnej z metod set i get_future (bez względu na to, czy będzie to rzutować, czy nie) jednocześnie, o ile widzę.