2013-05-06 5 views
7

Lesen des Dokuments von boost :: asio, es ist immer noch nicht klar, wenn ich asio :: strang verwenden muss. Angenommen, ich habe einen Thread mit io_service, ist es dann sicher, wie folgt auf einen Socket zu schreiben?Wann muss ich boost :: asio: strang verwenden

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; 
    } 
    } 
} 

Wo mehrere Threads ruft Connection :: write (..) oder muss ich Asio verwenden :: Strang?

Antwort

17

Kurze Antwort: Nein, Sie müssen in diesem Fall keine strand verwenden.

Grob vereinfacht enthält eine io_service eine Liste von Funktionsobjekten (Handlern). Handler werden in die Liste aufgenommen, wenn für den Dienst aufgerufen wird. z.B. Immer wenn eine asynchrone Operation abgeschlossen ist, werden der Handler und seine Argumente in die Liste aufgenommen. io_service::run() führt einen Handler nach dem anderen aus. Wenn also nur ein Thread run() aufruft, wie in Ihrem Fall, gibt es keine Synchronisationsprobleme und keine strand s werden benötigt.
Nur wenn mehrere Threads run() auf derselben io_service aufrufen, werden mehrere Handler gleichzeitig ausgeführt, in N Threads bis zu N gleichzeitige Handler. Wenn das ein Problem ist, z.B. Wenn sich gleichzeitig zwei Handler in der Warteschlange befinden, die auf dasselbe Objekt zugreifen, benötigen Sie die strand.
Sie können die strand als eine Art Sperre für eine Gruppe von Handlern sehen. Wenn ein Thread einen Handler ausführt, der einem strand zugeordnet ist, wird strand gesperrt, und es wird freigegeben, nachdem der Handler fertig ist. Jeder andere Thread kann nur Handler ausführen, die keinem gesperrten strand zugeordnet sind.

Vorsicht: diese Erklärung zu stark vereinfacht und genau technisch nicht sein kann, aber es gibt ein Grundkonzept, was passiert in den io_service und die strand s.

2

io_service::run() aus nur einem Thread aufrufen verursachen alle Event-Handler in dem Faden auszuführen, unabhängig davon, wie viele Threads Connection::write(...) sind aufruft. Daher ist es ohne eine gleichzeitige Ausführung von Handlern sicher. Die Dokumentation bezieht sich darauf als implicit strand.

Auf der anderen Seite, wenn mehrere Threads io_service::run() aufrufen, dann würde ein Strang notwendig werden. This Antwort deckt Strähnen in viel mehr Details.