본문 바로가기

BackEnd/C랑 C++

Error 해결: boost::shared_ptr<boost::asio::io_context>::operator*

boost thread를 활용하여 io_context_pool을 만들어서 사용하던 중.. core가 났다

이젠 놀랍지도 않은..

참고한 ThreadPool 예시는 아래에 첨부 링크로 올려두겠다

 

 

CMD> ./process
...
/usr/include/boost/smart_ptr/shared_ptr.hpp:728: typename boost::detail::sp_derr<T>::operator*() const [with T = boost::asio::io_context; typename boost::deta_context&]: Assertion `px != 0' failed.
Aborted (core dumped)

 

그러다 비슷한 에러를 가진 stack overflow 글을 보았는데 내용은 이러했다

 

일단 원인은, boost 에서 io_context를 얻어오는 함수인 get_executor() 사용시에

임시 객체로 얻어오는 경우에 core가 발생할 수 있다는 것이었다

 

auto ui_desktop  = std::make_shared<desktop>(ui_context.get_executor());

 

 

get_executor()는 안에가 어떻게 생겼냐면

 

/* io_context::get_executor */
executor_type get_executor();

 

그냥 요렇다

 

 

main 함수에서 임시객체 excutor에 get_executor()의 값을 저장해서 사용한다면

main 함수가 끝나면? 이 값은 유효하지 않게 되는 것이다...

그러고 이 값에 다시 접근하면 잘못된 메모리 접근을 해서 문제가 될 수 있다

라는 내용ㅋ

 

만약 어쩌다 잘 됐다 하더라도 원래 메모리라는게 그 크기만큼 공간이 잡히면

다시 그 메모리 주소에 접근 안하면 문제가 없어 보일 수도 있으니

방심하지말자

 

답변을 달아준 분은 해결 방법을 아래와 같이 달았다

 

ui_desktop 개체가 보유한 참조가 유효하도록

get_executor에서 반환된 실행자가 범위를 벗어나지 않는지 확인해라.

예를 들어, get_executor의 결과를 주 변수의 변수에 할당을 해라.

 

auto executor{ui_context.get_executor()};
auto ui_desktop = std::make_shared<desktop>(executor);

 

이렇게 ㅋ

 

참고) object { } 사용

C++ 11에 추가된 초기화 문법인데, 유니폼 초기화라고 부른다

int temp(0);은 안되지만 int temp{0}은 된다 ㅋ

 

 


위의 방법은 boost io_context를 좀더 잘 쓰기 위한 방법이니 참고 바라고,

boost 예시에 대한 추가적인 설명을 덧붙이고 끝내겠다

 

io_context_pool::io_context_pool(std::size_t pool_size)
  : next_io_context_(0)
{
  if (pool_size == 0)
    throw std::runtime_error("io_context_pool size is 0");

  // Give all the io_contexts work to do so that their run() functions will not
  // exit until they are explicitly stopped.
  for (std::size_t i = 0; i < pool_size; ++i)
  {
    io_context_ptr io_context(new boost::asio::io_context);
    io_contexts_.push_back(io_context);
    work_.push_back(boost::asio::require(io_context->get_executor(),
          boost::asio::execution::outstanding_work.tracked));
  }
}

 

아래 첨부에 링크를 둔 io_context_pool class의 생성자인데,

얘는 work_라는 net::io_context::work를 담아둔 vector에

위에서 언급한 get_executor()를 하나씩 넣어둔다

 

boost::asio::io_context& io_context_pool::get_io_context()
{
  // Use a round-robin scheme to choose the next io_context to use.
  boost::asio::io_context& io_context = *io_contexts_[next_io_context_];
  ++next_io_context_;
  if (next_io_context_ == io_contexts_.size())
    next_io_context_ = 0;
  return io_context;
}

 

그리고 io_context_pool class에 내부 함수로 get_io_context를 두어

미리 값을 저장한 io_context 값을 가져오도록 구현 되어 있다

 

실제 코드에서 사용할 때는 아래와 같이 사용하면 된다

 

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

 

 


* 참고한 Stack overflow 글 *

https://stackoverflow.com/questions/65534284/boost-asio-segfault-in-release-mode

 

Boost ASIO segfault in release mode

I have made this small illustrative code that exhibits the same issues the program I'm writing does: namely, it works fine in debug mode, segfaults in release. The problem seems to be that the ui_c...

stackoverflow.com

 

* boost thread pool example *

https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/example/cpp03/http/server2/io_context_pool.cpp

 

doc/html/boost_asio/example/cpp03/http/server2/io_context_pool.cpp - 1.78.0

 

www.boost.org