When do I need to use boost :: asio: strand

Reading the boost :: asio doc is not yet clear when I need to use asio :: strand. Suppose I have one thread using io_service, then is it safe to write it to a socket as follows?

void Connection::write(boost::shared_ptr<string> msg) { _io_service.post(boost::bind(&Connection::_do_write,this,msg)); } void Connection::_do_write(boost::shared_ptr<string> msg) { if(_write_in_progress) { _msg_queue.push_back(msg); } else { _write_in_progress=true; boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())), boost::bind(&Connection::_handle_write,this, boost::asio::placeholders::error)); } } void Connection::_handle_write(boost::system::error_code const &error) { if(!error) { if(!_msg_queue.empty()) { boost::shared_ptr<string> msg=_msg_queue.front(); _msg_queue.pop_front(); boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())), boost::bind(&Connection::_handle_write,this, boost::asio::placeholders::error)); } else { _write_in_progress=false; } } } 

If multiple threads access Connection :: write (..) or do I need to use asio :: strand?

+7
source share
2 answers

Short answer: no, you do not need to use strand in this case.

Widely simplified, io_service contains a list of function objects (handlers). Handlers are put on the list when post() is called in the service. for example, whenever an asynchronous operation completes, the handler and its arguments are put into a list. io_service::run() executes one handler after another. Therefore, if there is only one thread calling run() , as in your case, there is no synchronization problem, and there is no strand .
Only if several threads call run() on the same io_service , several handlers will be executed at the same time, in N threads - up to N simultaneous handlers. If this is a problem, for example, if there can be two handlers in the queue at the same time as accessing the same object, you will need strand .
You can see strand as a kind of lock for a group of handlers. If the thread runs the handler associated with strand , then strand blocked, and it is freed after the handler is executed. Any other thread can only execute handlers that are not associated with a locked strand .

Caution: this explanation may be too simplistic and technically inaccurate, but it gives a basic idea of ​​what happens in io_service and strand s.

+17
source

Calling io_service::run() from only one thread will cause all event handlers to be executed in the thread, regardless of how many threads call Connection::write(...) . Therefore, without the ability to execute handlers simultaneously, it is safe. The documentation refers to this as an implicit chain .

On the other hand, if multiple threads reference io_service::run() , then a chain is needed. This answer contains more details.

+2
source

All Articles