Skip to content

Instantly share code, notes, and snippets.

@redlizard

redlizard/cpp Secret

Created November 30, 2017 07:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save redlizard/cd537ec8f5e278e97293041a73572793 to your computer and use it in GitHub Desktop.
Save redlizard/cd537ec8f5e278e97293041a73572793 to your computer and use it in GitHub Desktop.
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <iostream>
using namespace boost;
/*
* wait_condition should have the API used here, with a release() function that can be invoked
* from a wait_condition reference in an arbitrary coroutine, without any earlier preparations
* in the releasing coroutine -- in particular, without any preparations done BEFORE the waiting
* thread invoked wait().
*/
class wait_condition
{
private:
typedef boost::asio::handler_type<boost::asio::yield_context, void()>::type handler_t;
public:
wait_condition(asio::io_service& ios):
m_ios(ios),
m_released(false),
m_handler(nullptr)
{}
void reset()
{
m_released = false;
}
void release()
{
m_released = true;
if (m_handler) {
m_ios.post(*m_handler);
}
}
void wait(boost::asio::yield_context yield)
{
if (!m_released) {
handler_t handler(std::forward<boost::asio::yield_context>(yield));
boost::asio::async_result<handler_t> result(handler);
m_handler = &handler;
result.get();
m_handler = nullptr;
}
}
private:
asio::io_service& m_ios;
bool m_released;
handler_t* m_handler;
};
int main()
{
asio::io_service ios;
asio::spawn(ios, [&ios](asio::yield_context yield) mutable {
wait_condition condition(ios);
asio::spawn(ios, [&ios, &condition](asio::yield_context yield) mutable {
asio::steady_timer timer(ios);
timer.expires_from_now(std::chrono::seconds(5));
timer.async_wait(yield);
condition.release();
});
condition.wait(yield);
std::cout << "done\n";
});
ios.run();
return 0;
}
@inetic
Copy link

inetic commented Nov 30, 2017

Here you go:

#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>

#include <iostream>

using namespace boost;

/*
 * wait_condition should have the API used here, with a release() function that can be invoked
 * from a wait_condition reference in an arbitrary coroutine, without any earlier preparations
 * in the releasing coroutine -- in particular, without any preparations done BEFORE the waiting
 * thread invoked wait().
 */
class wait_condition
{
	private:
	typedef asio::handler_type<asio::yield_context, void()>::type token_t;
	
	public:
	wait_condition(asio::io_service& ios):
		m_ios(ios),
		m_released(false),
		m_handler(nullptr)
	{}
	
	void reset()
	{
		m_released = false;
	}
	
	void release()
	{
		m_released = true;
		if (m_handler) {
			m_ios.post(std::move(m_handler));
		}
	}
	
	void wait(boost::asio::yield_context yield)
	{
		if (!m_released) {
			token_t token(std::forward<boost::asio::yield_context>(yield));
			boost::asio::async_result<token_t> result(token);
			
			m_handler = token;
			result.get();
			m_handler = nullptr;
		}
	}
	
	private:
	asio::io_service& m_ios;
	
	bool m_released;
	
	std::function<void()> m_handler;
};

int main()
{
	asio::io_service ios;
	
	asio::spawn(ios, [&ios](asio::yield_context yield) mutable {
		wait_condition condition(ios);
		
		std::cout << "start\n";

		asio::spawn(ios, [&ios, &condition](asio::yield_context yield) mutable {
			asio::steady_timer timer(ios);
			timer.expires_from_now(std::chrono::seconds(5));
			timer.async_wait(yield);
			
			condition.release();
		});
		
		condition.wait(yield);
		
		std::cout << "done\n";
	});
	
	ios.run();
	return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment