簡體   English   中英

std::future:異步單個生產者 + 任意數量的消費者問題

[英]std::future: Async single producer + any number of consumers problem

我想 model 一個異步操作產生一些T然后有多個調用在各個線程上獲取該T的問題。 這些調用將經常重復,因此即使在一個線程上,也會多次請求T

我首先考慮為此使用std::promise / std::future ,即

// Declaration
std::promise<T> p;
std::future<T> f = p.get_future();

// Producer code (different function)
p.set_value(...);

// Consumer code (different function; will be called repeatedly from different threads)
return f.get(); 

這里的問題是, future::get顯然是一次性操作,不能重復,所以我想到了shared_future::get() 但是shared_future在其文檔中提到:

如果每個線程都通過其自己的 shared_future object 副本進行訪問,則從多個線程訪問相同的共享 state 是安全的。

這看起來很奇怪,因為shared_future只有 const 方法,它應該始終是線程安全的,所以我認為這個own copy要求沒有任何必要。 我不知道會有多少線程,所以我不能為每個線程創建一個shared_future 消費者代碼可以在任何線程上重復調用。 做這個的最好方式是什么?

每當有人想使用T時,我可以即時創建一個shared_future副本嗎? IE:

// Declaration
std::promise<T> p;
std::shared_future<T> f = p.get_future();

// Producer code (different function)
p.set_value(...);

// Consumer code (different function; will be called repeatedly from different threads)
std::shared_future<T> fCopy = f; // Make a private copy of f on the stack.
return fCopy.get(); // Use the copy to get the T

這是應該怎么做的嗎? 復制構造shared_future線程安全嗎? 這會有很好的表現,還是我應該做不同的事情?

為我在評論回復中的錯誤建議道歉,但我認為你想要的是std::latch 初始化為 1,並且有任何等待它的東西調用wait()方法永遠等待直到它完成,或者try_wait()如果你不想永遠等待。

這就是我來自的地方:

int main(int argc, char* argv[])
{
    std::latch mylatch{ 1 };
    std::unique_ptr<int> common_source{};
    std::mutex sync_cout{};

    auto myTester = [&]() {
        mylatch.wait();
        std::lock_guard locker{ sync_cout };
        cout << "Through the latch, value is: " << *common_source << endl;
    };

    // Start the waiting threads
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; i++)
    {
        std::thread mythread{ myTester };
        threads.push_back(std::move(mythread));
    }

    cout << "Threads started" << endl;

    common_source = std::make_unique<int>(15);
    mylatch.count_down();

    std::this_thread::sleep_for(100ms);
    {
        std::lock_guard locker{ sync_cout };
        cout << "After count_down, starting a fresh thread to show it is let through" << endl;
    }
    {
        std::thread mythread{ myTester };
        threads.push_back(std::move(mythread));
    }

    // Wait for the threads to finish
    for (auto& curThread : threads)
    {
        curThread.join();
    }
    cout << "All threads down" << endl;
}

適應你認為合適的。 unique_ptr更改為您要分發的任何類型,並顯然鎖定以復制它,而不僅僅是輸出一個數字。 如果由於某種原因“處理程序”遲到(在它已經倒計時之后),它只是讓通過,就像你想要的那樣,而不是像我在我的例子中展示的那樣永遠等待。

By default, any function defined in the C++ standard library is considered to be thread-safe relative to some object if that function takes that object by pointer/reference to a const object. shared_future有一個復制構造函數,它通過const獲取引用。 因此,shared_future 的復制構造函數相對於從中復制它的shared_future是線程安全的,只要shared_future shared_future的所有其他操作也是線程安全的。

因此,只要您不對shared_future實例執行任何線程不安全的操作,您就可以從任何線程制作該實例的本地副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM