我需要呼叫作為遠程服務器請求的方法。之后我想等待答案,并且等待不會被其他異步函式/物件(例如計時器)阻止。
方法 got_response(...) 告訴用戶他從遠程服務器得到了一個答案,方法也獲取了我們作為答案得到的條目資料。下面我得到了我的解決方案,但有時可以在單執行緒中呼叫計時器,這將導致方法 got_response() 掛起。
如何在其他執行緒中呼叫計時器以保證答案模擬。我的問題還有其他解決方案嗎?
#include <iostream>
#include <boost/asio.hpp>
#include <future>
#include <thread>
#include <vector>
using namespace std;
namespace io = boost::asio;
struct Reply
{
atomic<bool> ready;
atomic<int> result;
future<void> future_result;
Reply()
{
ready = false;
result = 0;
}
void call()
{
cout << "retry called!" << endl;
future_result = async([&]()
{
while (!ready)
{
this_thread::yield();
}
});
}
int get()
{
future_result.wait();
return result.load();
}
void got_response(int res)
{
result = res;
ready = true;
}
};
int main()
{
Reply reply;
reply.call();
io::io_context context(4);
io::steady_timer timer1(context, std::chrono::seconds(2));
timer1.async_wait([&](const boost::system::error_code &ec)
{ cout << "timer 1, thread name: " << this_thread::get_id() << endl; });
io::steady_timer timer2(context, std::chrono::seconds(3));
timer2.async_wait([&](const boost::system::error_code &ec)
{
cout << "timer 2, thread name: " << this_thread::get_id() << endl;
cout << reply.get() << endl;
});
io::steady_timer timer3(context, std::chrono::seconds(10));
timer3.async_wait([&](const boost::system::error_code &ec)
{
cout << "timer 3, thread name: " << this_thread::get_id() << endl;
reply.got_response(1337);
});
vector<thread> threads;
auto count = 2;
for (int n = 0; n < count; n)
{
threads.emplace_back([&]
{ context.run(); });
}
for (auto &th : threads)
{
th.join();
}
}
結果:
retry called!
timer 1, thread name: 140712511198784
timer 2, thread name: 140712519591488
timer 3, thread name: 140712511198784
1337
uj5u.com熱心網友回復:
哇。這在幾個層面上過于復雜。
期貨可以有型別的回傳值(這實際上是未來同步原語的全部意義)
fturue 可以用一個值表示準備就緒,無需將準備就緒復制到 a 中
bool,然后將結果復制到某處這讓我很困惑:
int get() { _fut.wait(); return _result.load(); }它等待未來,然后回傳
_result,你知道你發明_ready了什么嗎?您是否意識到這
std::async不是 Boost ASIO 的一部分?事實上,它不能很好地與它一起作業,因為正如您正確注意到的那樣,它引入了(未指定數量的)執行緒。一般來說,我的建議是不要使用std::async(很難正確使用),而且在使用 ASIO 時絕對不要使用當您看到相同的變數名稱 var1、var2、var3 時,是時候重構您的代碼(如果它包含資料成員,則重構為函式或類):
std::deque<io::steady_timer> timers; for (int i = 1; i <= 3; i) { auto& timer = timers.emplace_back(context, std::chrono::seconds(1 i)); timer.async_wait([i](error_code ec) { std::cout << "timer " << i << ", thread name: " << std::this_thread::get_id() << std::endl; }); }而不是執行緒向量,請考慮
boost::thread_group或 確實boost::asio::thread_pool。如果你手動運行 IO 執行緒,記得處理例外(是否應該捕獲 boost::asio::io_service::run() 拋出的例外?),所以
boost::thread_group threads; for (int n = 0; n < 2; n) { threads.create_thread([&] { context.run(); }); } threads.join_all();或者確實
io::thread_pool context(2); context.join();這是非常低效的
while (!_ready) { std::this_thread::yield(); }只需設定未來值以表示它已準備就緒:
using namespace std通常不是一個好主意(為什么“使用命名空間標準;”被認為是不好的做法?)
演示
這是我對問題代碼的擴展但簡化的看法:
住在 Coliru
#include <boost/asio.hpp>
#include <deque>
#include <future>
#include <iostream>
#include <thread>
namespace io = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
// not very useful in practice, but for debug output in main
std::ostream& debug(error_code);
template <typename Fut> bool is_ready(Fut const& fut) {
return fut.wait_for(0s) == std::future_status::ready;
}
int main() {
std::promise<int> reply;
std::shared_future got_value = reply.get_future();
io::thread_pool context(2);
std::deque<io::steady_timer> timers;
for (int i = 1; i <= 10; i) {
timers //
.emplace_back(context, i * 1s)
.async_wait([&got_value](error_code ec) {
if (is_ready(got_value))
debug(ec) << " Reply:" << got_value.get() << std::endl;
else
debug(ec) << " (reply not ready)" << std::endl;
});
}
timers //
.emplace_back(context, 4'500ms)
.async_wait([&reply](error_code ec) {
debug(ec) << " setting value" << std::endl;
reply.set_value(1337);
});
context.join();
}
int friendly_thread_id() {
return std::hash<std::thread::id>{}(std::this_thread::get_id()) % 256;
}
#include <iomanip>
std::ostream& debug(error_code ec) {
auto now = std::chrono::system_clock::now;
static auto program_start = now();
return std::cout //
<< ((now() - program_start) / 1ms) << "ms\t"
<< "thread:" << std::hex << std::setfill('0') << std::showbase
<< std::setw(2) << friendly_thread_id() << std::dec << " ";
}
#include <iomanip>
std::ostream& debug(error_code ec) {
auto now = std::chrono::system_clock::now;
static auto program_start = now();
return std::cout //
<< ((now() - program_start) / 1ms) << "ms\t"
<< "thread:" << std::hex << std::setfill('0') << std::showbase
<< std::setw(2) << pretty_thread_id() << std::dec << " ";
}
印刷
0ms thread:0x5f (reply not ready)
999ms thread:0xf3 (reply not ready)
1999ms thread:0x5f (reply not ready)
2999ms thread:0x5f (reply not ready)
3499ms thread:0xf3 setting value
3999ms thread:0x5f Reply:1337
4999ms thread:0xf3 Reply:1337
5999ms thread:0xf3 Reply:1337
6999ms thread:0xf3 Reply:1337
7999ms thread:0xf3 Reply:1337
8999ms thread:0xf3 Reply:1337
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/318763.html
上一篇:為什么從并發佇列異步呼叫`DispatchQueue.main.sync`成功但同步失敗?
下一篇:多次啟動執行緒
