2013-01-23 103 views
1

我只想讓一個聊天客戶端異步地從套接字偵聽,並從boost::asio::posix::stream_descriptor分配給stdin。從套接字和STDIN提升ASIO多線程

如果我在單線程應用程序中運行此代碼,所有工作正常。

如果我從2個或更多線程調用io_service.run(),那麼來自stdin的異步操作永遠不會好,但仍會執行來自套接字的異步讀取。

這裏是代碼:

MasterClient::MasterClient(boost::asio::io_service& io_service,boost::asio::ip::tcp::resolver::iterator iter, string nickName) 
:it(iter),chatNick(nickName) 
{ 
    this->fdIn_ = str_ptr(new boost::asio::posix::stream_descriptor(io_service,::dup(STDIN_FILENO))); 
    this->dirServer_ = new(connectedPeer); 
    this->dirServer_->sock = socket_ptr(new boost::asio::ip::tcp::socket(this->io_service_)); 
    boost::asio::async_connect(*(this->dirServer_->sock), this->it, 
     boost::bind(&MasterClient::connectionHandler, this, 
       boost::asio::placeholders::error)); 
} 

主:

int main(int argc, const char * argv[]) 
{ 
boost::asio::io_service io_service(2); 
    boost::asio::io_service::work work(io_service); 
    boost::asio::ip::tcp::resolver resolver(io_service); 
    boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]); 
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); 
    string nick; 
    cout << "Inserire un nickname per la sessione di chat: " << flush; 
    getline(cin,nick); 
    MasterClient cli(io_service,iterator,nick); 
cli.run(); 
} 

和MasterClient :: run()的

void MasterClient::run() 
{ 
// Create a pool of threads to run all of the io_services. 
std::vector<boost::shared_ptr<boost::thread> > threads; 
boost::asio::io_service::work work(this->io_service_); 
for (std::size_t i = 0; i < 1; ++i) 
{ 
    boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_))); 
    threads.push_back(thread); 
} 


// Wait for all threads in the pool to exit. 
for (std::size_t i = 0; i < threads.size(); ++i) 
    threads[i]->join(); 
} 

這裏我所說的異步讀數:

void MasterClient::clientDelegate() 
{ 
if(this->connectToServer()) 
{ 
    this->mainMenu(); 

    boost::asio::async_read_until(*fdIn_, inBuff_, '\n', 
      boost::bind(&MasterClient::fdInMenuHandler, 
        this, 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred)); 

    (*(this->dirServer_->sock)).async_read_some(boost::asio::buffer(this->buff_), 
      boost::bind(&MasterClient::serverHandler, 
        this, 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred, 
        this->dirServer_->sock)); 
    this->io_service_.post(boost::bind(&MasterClient::printer,this)); 
}else 
{ 
    if(this->isDebugging) 
     cout << "Error in ClientDelegate." << endl; 
} 
if(this->isDebugging) 
    cout << "ClientDelegate END" << endl; 
} 

連接處理程序,其中clientDelegate被調用:

void MasterClient::connectionHandler(const boost::system::error_code& error) 
{ 
cout << "connected" << endl; 
try 
{ 
    if(error) 
     throw boost::system::system_error(error); 
    else 
    { 
     this->dirServer_->endpoint = boost::asio::ip::tcp::endpoint((*(this->dirServer_->sock)).remote_endpoint()); 
     this->clientDelegate(); 
    } 
}catch(const boost::system::system_error& e) 
{ 
    cerr << "Boost Exception in ConnectHandler ---> " << e.what() << endl; 
    this->io_service_.stop(); 
} 
} 

我到底做錯了什麼?

回答

1

根據boost::asio::posix::stream_descriptor的文檔,從多個線程使用相同的實例是不安全的。在多線程的情況下,處理程序通常會被包裝成串行化的串。

在你的情況下,我沒有看到爲同一個客戶端連接使用多個線程的要點。

+0

根據boost asio文檔,如果我將io_service.run調用到多個線程中,那些線程有資格調用處理程序。我錯了嗎? –

+0

是的,從多個線程調用同一個io_service的run方法是安全的。然而,處理程序可以同時調用,所以你需要小心。 Asio提供的鏈可以幫助您在多線程程序中連續處理程序。 – jcm

+0

目前還不清楚你的程序鏈是如何處理的。 clientDelegate在哪裏打電話? fdInMenuHandler做什麼?在一個客戶端連接中使用多線程看起來很奇怪。爲什麼不單線程? – jcm