[Boost.Asio] io_service, threads, handler example

This sample code using Boost.Asio sets up 3 worker threads and pretends to monitor the connection status of 10 servers. The main function kicks it off by asking io_service to run  GetConnectionStatus. GetConnectionStatus then use a timer to do it again in 10 seconds forever, until someone terminates the program.

The code below commented out service.post. If it is uncommented (and if we removed the timer code in ConnectionStatusChanged), then ConnectionStatusChanged maybe called in the context of a different thread than the one calling GetConnectionStatus.

// Declarations
void ConnectionStatusChanged(std::string status, int name);
void GetConnectionStatus(int name);

// io_service is the abstraction between our code and the OS
io_service service;

void worker_thread(){
	std::cout << std::this_thread::get_id() << ": starting worker thread." << std::endl;
	service.run(); // this is blocking
	std::cout << std::this_thread::get_id() << ": stopping worker thread." << std::endl;
}

void GetConnectionStatus(int name)
{
	std::cout << std::this_thread::get_id() << ": Pulling status of server " << name << std::endl;
	std::string newStatus;

	// randomly picks online/offline... and say it takes random amount of time to get status
	sleep(rand() % 3 + 1);
	(rand() % 2) ? newStatus = "online" : newStatus = "offline";
	
	// notify new status
	ConnectionStatusChanged(newStatus, name);
	//service.post(boost::bind(ConnectionStatusChanged, newStatus, name));
}

void ConnectionStatusChanged(std::string status, int name)
{
	std::cout << std::this_thread::get_id() << ": Server " << name << " " << status << std::endl;

	// Get status again in 10 seconds
	deadline_timer timer(service);
	timer.expires_from_now(boost::posix_time::seconds(10));
	timer.async_wait(boost::bind(GetConnectionStatus, name));
	//service.post(boost::bind(GetConnectionStatus, name));
}


int main(int argc, char* argv[])
{
	io_service::work work(service); // io_service::work prevents io_service::run from returning even if there's no more work
	std::vector threads;

	// In this example we have more servers than we have threads.

	// Start 3 threads
	for ( int i = 0; i < 3; ++i)
	{
		threads.push_back(std::thread(worker_thread));
	}

	sleep(1); // Wait for threads to start

	// Say we have 10 servers to monitor
	for( int i = 0; i < 10; ++i)
	{
		// notice that GetConnectionStatus and ConnectionStatusChanged schedules each other to be called
		service.post(boost::bind(GetConnectionStatus, i));
	}

	for( auto& t : threads )
	{
		t.join();
	}
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s