Rebuild、reconnect promise-future channel
1、我的应用中,需要重复地登录、接收登录响应,它是Asynchronous IO + callback,为了处理方便我使用promise-future channel来实现"async to sync-blocking-等待",简化处理;后来基于它开发了一个交互式的application,在这个application可能需要重复进行登录,此时会抛出:
std::future_errc promise_already_satisfied
2、后来经过查阅方才知道:
对于一个promise对象,std::promise
3、那如何实现我的重复使用的目的呢?方法是: "rebuild、reconnect promise-future channel"
经过实践,下面是我的最终程序:
#include <future>
#include <chrono>
#include <thread>
#include <sstream>
#include <iostream>
#define LOG(...) LogWrapper(__FILE__, __LINE__, __VA_ARGS__)
// Terminator
void Log_Recursive(const char *file, int line, std::ostringstream &msg)
{
std::cout << file << "(" << line << "): " << msg.str() << std::endl;
}
// "Recursive" variadic function
template<typename T, typename ... Args>
void Log_Recursive(const char *file, int line, std::ostringstream &msg, T value, const Args &... args)
{
msg << value;
Log_Recursive(file, line, msg, args...);
}
// Log_Recursive wrapper that creates the ostringstream
template<typename ... Args>
void LogWrapper(const char *file, int line, const Args &... args)
{
std::ostringstream msg;
Log_Recursive(file, line, msg, args...);
}
class Test
{
std::future<bool> m_ConnectResultFuture;
std::promise<bool> m_ConnectResultPromise;
bool m_ConnectedFlag { false };
std::future<void> m_SendRspTask;
public:
bool Init()
{
m_ConnectResultPromise = std::promise<bool>();
m_ConnectResultFuture = m_ConnectResultPromise.get_future(); // 建立future-promise channel
m_SendRspTask = std::async(std::launch::async, [this]
{
std::this_thread::sleep_for(std::chrono::seconds(2));
this->m_ConnectResultPromise.set_value(true);
}
);
std::future_status status = m_ConnectResultFuture.wait_for(std::chrono::seconds(3));
if (status == std::future_status::deferred)
{
LOG("未知状态,将等待3S(可能会连接超时)");
std::this_thread::sleep_for(std::chrono::seconds(3));
m_ConnectedFlag = true;
}
else if (status == std::future_status::timeout)
{
LOG("连接超时了");
m_ConnectedFlag = true;
}
else if (status == std::future_status::ready)
{
m_ConnectedFlag = m_ConnectResultFuture.get();
if (m_ConnectedFlag)
{
LOG("连接成功了!");
}
else
{
LOG("连接失败了!");
}
}
return m_ConnectedFlag;
}
};
int main()
{
Test t;
t.Init();
t.Init();
return 0;
}
// g++ --std=c++11 test.cpp -Wall -Wextra -pedantic -lpthread
cppreference std::promise::set_value
NOTE:
1、这里面已经讨论了thread safety问题
stackoverflow How do I “clear” std::promise?
A
To reuse promises, simply reassign them.
std::promise<int> my_promise;
//use the promise
my_promise = std::promise<int>(); //now you have a new promise
NOTE:
1、然后需要重新建立promise-future channel
stackoverflow std::promise set_value and thread safety
NOTE:
1、非常好的topic
A
NOTE:
1、非常好的回答