asio多线程环境 io_service和strand搭配使用

梦想游戏人
目录:
C/C++

一个io_service对象可以通过多个线程调用io_service.run进行事件处理器的并发。分发到不同的线程上执行的策略可以认为是随机的。

strand是线程安全的任务队列的封装,具体执行还是会调用io_service的接口进行处理。一个io_service可以被多个strand绑定。

因此strand的特性是保证同一个strand里面的任务是按序执行,任务执行的线程是根据io_server.run线程分配的,所以一个strand里面的任务执行的线程并不一定是同一个。

下面是strand.post具体实现:

void strand_service::do_post(implementation_type& impl,
    operation* op, bool is_continuation)
{
  impl->mutex_.lock();
  if (impl->locked_)
  {
    // Some other handler already holds the strand lock. Enqueue for later.
    impl->waiting_queue_.push(op);
    impl->mutex_.unlock();
  }
  else
  {
    // The handler is acquiring the strand lock and so is responsible for
    // scheduling the strand.
    impl->locked_ = true;
    impl->mutex_.unlock();
    impl->ready_queue_.push(op);
    io_service_.post_immediate_completion(impl, is_continuation);
  }
}

使用例子:

int main(int argc, char* argv[])
{
	io_service io;
	io_service::work worker(io);

	for (int i = 0; i < 3; i++)
	{
		std::thread t([&](){io.run(); });
		t.detach();
	}
	boost::asio::strand str1(io);

	// step 1
	for (int i = 0; i < 10; i++)
	{
		io.post([=]()
		{
			cout << i << endl;
		});
	}

	std::this_thread::sleep_for(std::chrono::seconds(1));
	cout << "AAAAAAAAAAAAAAAAAAAAA" << endl;

	// step 2
	for (int i = 0; i < 10; i++)
	{
		str1.post([=]()
		{
			cout << i << " tid:" << std::this_thread::get_id() << endl;
		});
	}

	::system("pause");
	return 0;
}

输出:

使用例子中的step1是直接使用io_service进行任务分发,因此执行顺序是乱序的。

使用例子中的step2是通过strand封装进行任务分发,因此是顺序执行,执行的线程也不一定是同一个。

Scroll Up