Multithreading boost库多线程套接字奇怪性

Multithreading boost库多线程套接字奇怪性,multithreading,boost,Multithreading,Boost,我被困了一整晚,但没能找出问题所在 我正在编写一个服务器,它接受聊天室应用程序的连接。其思想是,服务器将连接的套接字提供给chat_manager,chat_manager将其放入等待列表,并启动一个线程不断检查是否有人仍在等待列表中。如果有人在等待列表中,聊天室管理员会尝试读取客户的信息,以确定客户想要加入哪个房间 main.cpp如下所示: boost::asio::io_service io_service; chat_server server(io_service, 8091); io

我被困了一整晚,但没能找出问题所在

我正在编写一个服务器,它接受聊天室应用程序的连接。其思想是,服务器将连接的套接字提供给chat_manager,chat_manager将其放入等待列表,并启动一个线程不断检查是否有人仍在等待列表中。如果有人在等待列表中,聊天室管理员会尝试读取客户的信息,以确定客户想要加入哪个房间

main.cpp如下所示:

boost::asio::io_service io_service;
chat_server server(io_service, 8091);
io_service.run();
聊天服务器代码:

chat_server::chat_server(boost::asio::io_service& io_service, int port) : io_service_(io_service), 
    acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) {
    start_accept();
}
void chat_server::start_accept() {
    chat_session_ptr new_session(new chat_session(io_service_));

    acceptor_.async_accept(new_session->socket(), boost::bind(&chat_server::handle_accept, this, new_session, 
        boost::asio::placeholders::error));
}
void chat_server::handle_accept(chat_session_ptr s, const boost::system::error_code& error) {
    if (!error) {       // successfully connected
        chat_manager::Instance().chat_session_join(s);
    }

    start_accept();
}
聊天室经理很简单

chat_manager() { // constructor
    waitlist_.resize(0);
    manager_thread_ = boost::thread(&chat_manager::run, this);
}

int chat_session_join(chat_session_ptr chat_session) {
    mutex_.lock();
    waitlist_.push_back(chat_session);
    mutex_.unlock();
    return 1;
}

void run() {
    while (1) {
        mutex_.lock();
        for (auto &s : waitlist_) {
            std::string roomname;
            if (s->wait_for_join(roomname)) {
                ...
            }

            break;
        }
        mutex_.unlock();

        boost::this_thread::sleep( boost::posix_time::milliseconds(10) );
    }
}
和session.cpp:

jsoncons::json chat_session::receive_request(boost::system::error_code& error) {

    buffer_.consume(buffer_.size());

    size_t bytes_transferred;
    boost::system::error_code ec = boost::asio::error::would_block;

    boost::asio::async_read_until(socket_, buffer_, "\n", 
            boost::bind(&chat_session::handle_read, shared_from_this(), _1, _2, &ec, &bytes_transferred ));

    deadline_.expires_from_now(boost::posix_time::seconds(2));
    deadline_.async_wait(boost::bind(&chat_session::check_deadline, shared_from_this()));

    do pio_service_->run_one(); while (ec == boost::asio::error::would_block);

    std::cout << "got it" << std::endl;

    if ( ec || !socket_.is_open() ) {
        std::cout << ec.message() << std::endl;
        return jsoncons::json();
    }

    std::istream is(&buffer_);

    return jsoncons::json::parse(is);
}

int chat_session::wait_for_join(std::string &roomname) {
    boost::system::error_code error;
    jsoncons::json request = receive_request(error);
    ...
}

void chat_session::handle_read(const boost::system::error_code& error, size_t bytes_transferred, 
    boost::system::error_code* out_error, size_t* out_bytes_transferred) {

    deadline_.expires_at(boost::posix_time::pos_infin);

    *out_error = error;
    *out_bytes_transferred = bytes_transferred;

    if (!error) {
    } else {
        std::cout << "handle_read error:" << error.message() << std::endl;
    }
}
jsons::json聊天会话::接收请求(boost::system::error\u代码和错误){
缓冲区消耗(缓冲区大小());
传输的字节大小;
boost::system::error\u code ec=boost::asio::error::would\u block;
boost::asio::异步\u读取\u直到(套接字\u,缓冲区\u,“\n”,
boost::bind(&chat_session::handle_read,shared_from_this(),_1,_2,&ec,&bytes_transfer));
截止日期从现在起过期(boost::posix_time::seconds(2));
截止期\异步\等待(boost::bind(&chat\ u session::check\ u deadline,shared\ u from\ u this());
do pio_service_uu->run_one();while(ec==boost::asio::error::would_block);

std::粗略猜测,您希望在主线中创建并运行的io_服务也在线程中运行。它们没有。简单的回答是,您为什么要费心使用线程?您已经在io_服务中运行了一个完整的事件系统。让它运行(),放弃对线程的虚假和过度使用,只需对传入和传出的通信使用异步处理程序。这实际上是我第一次编写服务器,所以我不确定通常是如何完成的。最终我希望每个聊天室都能独立运行,这样,如果一个聊天室崩溃,服务器就不会崩溃。但我知道没有办法将一个已建立的套接字交给另一个聊天室另一个程序,所以我决定改用线程。一旦我将套接字交给聊天室,聊天室应该处理通信,而不是服务器。我在某个地方读到,在多个线程中使用单个io_服务是可以的,因为在main.cpp中,它一直接受新的连接,所以运行()从不终止且始终有效。但在线程中,我调用了run_one(),即使作业已完成(handle_read),它似乎也会由于未知原因而阻塞。我现在猜测,主线程的io_服务。run()处理了handle_read作业,但收到了\u请求的run_one()未收到通知,因此它在等待另一个事件的while循环中被阻止。将run_one()替换为sleep(10)可解决此问题。这将是一个睡眠(0)会做同样的事情-允许一个上下文切换到主线程。尝试一下-当核心命中100%时,它会显示实际的轮询开销。由于线程有效地使用共享内存空间的方式,您的线程正在访问主线程中的数据并连接到io_服务。它们还完成大部分工作(即io)在主线程中。如果它们不在线程中,您实际上会更安全。您真正做的就是增加使用互斥锁保护数据的额外复杂性