2017-03-28 2 views
0

내 서버는 boost spawn echo server을 기반으로합니다.io_service-per-CPU를 사용하여 boost :: asio :: spawn을 수행하는 방법은 무엇입니까?

서버가 단일 코어 컴퓨터에서 제대로 실행되며 몇 달 동안 하나의 충돌이 발생하지 않습니다. 100 % CPU를 사용하는 경우에도 여전히 잘 작동합니다.

하지만 이제는 더 많은 클라이언트 요청을 처리해야합니다. 이제는 멀티 코어 시스템을 사용합니다. 이런 내가 여러 스레드에서 io_service를 실행하는 모든 CPU를 사용하려면 :

#include <boost/asio/io_service.hpp> 
#include <boost/asio/ip/tcp.hpp> 
#include <boost/asio/spawn.hpp> 
#include <boost/asio/steady_timer.hpp> 
#include <boost/asio/write.hpp> 
#include <boost/thread/thread.hpp> 
#include <iostream> 
#include <memory> 
#include <thread> 
using namespace std; 

using boost::asio::ip::tcp; 

class session : public std::enable_shared_from_this<session>{ 
public: 
    explicit session(tcp::socket socket) 
     : socket_(std::move(socket)), 
     timer_(socket_.get_io_service()), 
     strand_(socket_.get_io_service()) 
    {} 

    void go() 
    { 
     auto self(shared_from_this()); 
     boost::asio::spawn(strand_, [this, self](boost::asio::yield_context yield) 
     { 
      try { 
       char data[1024] = {'3'}; 
       for(; ;) { 
        timer_.expires_from_now(std::chrono::seconds(10)); 
        std::size_t n = socket_.async_read_some(boost::asio::buffer(data, sizeof(data)), yield); 
        // do something with data 
        // write back something 
        boost::asio::async_write(socket_, boost::asio::buffer(data, sizeof(data)), yield); 
       } 
      } catch(...) { 
       socket_.close(); 
       timer_.cancel(); 
      } 
     }); 

     boost::asio::spawn(strand_, [this, self](boost::asio::yield_context yield) 
     { 
      while(socket_.is_open()) { 
       boost::system::error_code ignored_ec; 
       timer_.async_wait(yield[ignored_ec]); 
       if(timer_.expires_from_now() <= std::chrono::seconds(0)) 
        socket_.close(); 
      } 
     }); 
    } 

private: 
    tcp::socket socket_; 
    boost::asio::steady_timer timer_; 
    boost::asio::io_service::strand strand_; 
}; 

int main(int argc, char* argv[]) { 
    try { 

     boost::asio::io_service io_service; 

     boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) 
     { 
      tcp::acceptor acceptor(io_service, 
#define PORT "7788" 
      tcp::endpoint(tcp::v4(), std::atoi(PORT))); 

      for(; ;) { 
       boost::system::error_code ec; 
       tcp::socket socket(io_service); 
       acceptor.async_accept(socket, yield[ec]); 
       if(!ec) 
        // std::make_shared<session>(std::move(socket))->go(); 
        io_service.post(boost::bind(&session::go, std::make_shared<session>(std::move(socket)))); 
      } 
     }); 

     // ----------- this works fine on single-core machine ------------ 
     { 
      // io_service.run(); 
     } 

     // ----------- this crashes (with multi core) ---------- 
     { 
      auto thread_count = std::thread::hardware_concurrency(); // for multi core 
      boost::thread_group threads; 
      for(auto i = 0; i < thread_count; ++i) 
       threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service)); 

      threads.join_all(); 
     } 

    } catch(std::exception& e) { 
     std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
코드는 싱글 코어 maching에 잘 작동하지만 2 코어/4 코어/8 코어 시스템의 모든 시간을 충돌

. 크래시 덤프에서 나는 내 코드와 관련된 것을 보지 못했다. boost :: spawn과 무작위로 명명 된 람다에 관한 것이다.

그래서 이것을 시도하고 싶습니다. CPU 당 io_service을 실행하십시오.

는 좀 demo을 발견하지만, 비동기 기능을 사용

void server::start_accept() 
{ 
    new_connection_.reset(new connection(
     io_service_pool_.get_io_service(), request_handler_)); 
    acceptor_.async_accept(new_connection_->socket(), 
     boost::bind(&server::handle_accept, this, 
     boost::asio::placeholders::error)); 
} 

void server::handle_accept(const boost::system::error_code& e) 
{ 
    if (!e) 
    { 
    new_connection_->start(); 
    } 

    start_accept(); 
} 

io_service_pool_.get_io_service() 무작위로 픽업 io_service,하지만 내 코드는 임의 io_servicespawn

boost::asio::spawn(io_service, ... 

방법 spawn 사용을?

+0

여러 개의 스레드에서 실행되는 하나의'io_service'가 있어야한다고 생각합니다. 스레드 당'io_service'를 가지고 있다면 왜'strand'를 가질 수 있습니까? –

+0

부스트의 예제에서 코드를 복사했는데 실제로'spawn'을 이해하지 못했습니다.'strand '함수를 사용하여'go' 함수에서 두 개의'spawn'이 순서대로 실행되는지 확인합니다. – aj3423

+0

Strand는 함수가 동시에 실행되지 않도록 io_service 대기열의 함수 래퍼입니다. 비 차단 뮤텍스와 비슷합니다. io_service와 strand에 대해 조금 읽으십시오. 이 충고에 대해 저에게 감사드립니다. –

답변

0

내가 잘못된 질문을하고있는 것처럼 보입니다. spawn은 복수 io_service으로 작동하지 않지만, socket은 사용할 수 없습니다. 코드를 다음과 같이 수정했습니다.

int main(int argc, char* argv[]) { 
    try { 

     boost::asio::io_service io_service; 
     boost::asio::io_service::work work(io_service); 

     auto core_count = std::thread::hardware_concurrency(); 
     // io_service_pool.hpp and io_service_pool.cpp from boost's example 
     io_service_pool pool(core_count); 

     boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) 
     { 
#define PORT "7788" 
      tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), std::atoi(PORT))); 

      for(; ;) { 
       boost::system::error_code ec; 
       boost::asio::io_service& ios = pool.get_io_service(); 
       tcp::socket socket(ios); 
       acceptor.async_accept(socket, yield[ec]); 
       if(!ec) 
        ios.post(boost::bind(&session::go, std::make_shared<session>(std::move(socket)))); 
      } 
     }); 

     { // run all io_service 
      thread t([&] { pool.run(); }); 
      t.detach(); 

      io_service.run(); 
     } 

    } catch(std::exception& e) { 
     std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

이제 서버가 더 이상 충돌하지 않습니다. 그러나 모든 스레드에 단일 io_service을 사용하면 충돌을 일으킬 수있는 원인을 알 수 없습니다.

관련 문제