2013-05-06 15 views
7

Leggendo il documento di boost :: asio, non è ancora chiaro quando ho bisogno di usare asio :: strand. Supponiamo che io abbia un thread usando io_service è sicuro scrivere su un socket come segue?Quando devo usare boost :: asio: strand

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

Dove più thread chiama Connection :: Write (..) o devo usare ASIO :: Strand?

risposta

17

Risposta breve: no, non è necessario utilizzare uno strand in questo caso.

Ampiamente semplificato, un io_service contiene un elenco di oggetti funzione (gestori). I gestori vengono inseriti nell'elenco quando viene chiamato il servizio post(). per esempio. ogni volta che un'operazione asincrona viene completata, il gestore e i relativi argomenti vengono inseriti nell'elenco. io_service::run() esegue un gestore dopo l'altro. Quindi, se c'è solo un thread che chiama run() nel tuo caso, non ci sono problemi di sincronizzazione e non sono necessari i numeri strand s.
Solo se più thread chiamano run() sullo stesso io_service, più gestori verranno eseguiti contemporaneamente, in N thread fino a N gestori simultanei. Se questo è un problema, ad es. se potrebbero esserci due gestori in coda contemporaneamente che accedono allo stesso oggetto, è necessario lo strand.
È possibile vedere lo strand come una sorta di blocco per un gruppo di gestori. Se un thread esegue un gestore associato a un strand, quel strand viene bloccato e viene rilasciato dopo il completamento del gestore. Qualsiasi altro thread può eseguire solo gestori non associati a uno strand bloccato.

Attenzione questa spiegazione può essere eccessivamente semplificato e tecnicamente non accurate, ma dà un concetto di base di ciò che accade nel io_service e delle strand s.

2

Chiamare io_service::run() da un solo thread causerà l'esecuzione di tutti i gestori di eventi all'interno del thread, indipendentemente dal numero di thread che invoca Connection::write(...). Pertanto, senza alcuna possibile esecuzione simultanea di gestori, è sicuro. La documentazione si riferisce a questo come implicit strand.

D'altra parte, se più thread stanno invocando io_service::run(), diventa necessario un filamento. La risposta This copre i fili in modo molto più dettagliato.