Как использовать Handler и boost::asio::async_result

Как использовать boost::asio::async_result, почему мой код вылетает из-за (прервано сигналом 11: SIGSEGV)

using ReadSignature = void(int);
template <class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken , ReadSignature)
AsyncRead(boost::asio::io_service* ios,CompletionToken&& token) {
  using Handler = typename boost::asio::handler_type<CompletionToken,
                                                 ReadSignature>::type;
  Handler handler(std::forward<CompletionToken>(token));
  boost::asio::async_result<Handler> result(handler);

  std::cout << std::time(nullptr) << ":before thread" << std::endl;

  std::thread thread([ios,&handler]() {
    std::cout << std::time(nullptr) << ":run in thread before sleep"<< std::endl;
    sleep(5);
    std::cout << std::time(nullptr) << ":run in thread after sleep"<< std::endl;
    std::cout << std::time(nullptr) << ":run in thread before cb" << std::endl;
    ios->post([&handler](){
      handler(2);
    });
    std::cout << std::time(nullptr) << ":run in thread after cb"<<std::endl;
  });
  thread.detach();
  return result.get();
}

int main(int argc, char** argv) {
  boost::asio::io_service s;
  boost::asio::io_service::work worker(s);
  boost::asio::spawn(s,[&s](boost::asio::yield_context yield){
    boost::system::error_code er;
    int val=AsyncRead(&s,yield[er]);
    std::cout << std::time(nullptr) <<"get:"<<val<< "" << std::endl;
  });

  s.run();
  return 0;
}

Я ожидаю: вернуть результат.get(); даст волокно, и значение 2 получит. но сбой кода с: (прервано сигналом 11: SIGSEGV), потому что handler.ec равен нулю.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
712
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Этим

ios->post([&handler](){
      handler(2);
    });

вы создаете лямбду, которая ставится в очередь в io_service. Это закрытие выполняется внутри io_service::run. Вы захватываете по ссылке handler, которая является локальной внутри AsyncRead. Когда handler(2) вызывается

AsyncRead(&s,yield[er]);

сопрограмма возобновляется в строке выше, result.get() вызывается из AsyncRead, AsyncRead завершается, и обработчик как локальная переменная уничтожается, но замыкание, которое выполняется в io_service::run, по-прежнему ссылается на эту переменную - поведение undefined.

Вам нужно захватить обработчик по значению, переместив его в поток и лямбда:

  std::thread thread([ios,handler = std::move(handler)]() {
    std::cout << std::time(nullptr) << ":run in thread before sleep"<< std::endl;
    sleep(5);
    std::cout << std::time(nullptr) << ":run in thread after sleep"<< std::endl;
    std::cout << std::time(nullptr) << ":run in thread before cb" << std::endl;
    ios->post([handler = std::move(handler)]() mutable {
      handler(2);
    });
    std::cout << std::time(nullptr) << ":run in thread after cb"<<std::endl;
  });

'результат.получить();' даст AsyncRead, почему локальная переменная «обработчик» уничтожена?

Zhigang Zhang 31.05.2019 09:22

Этот Handler handler(std::forward<CompletionToken>(token)); создает handler как локальную переменную внутри AsyncRead функции. Когда выполняется следующее закрытие [&handler](){ handler(2); });, оно вызывает handler(2), затем result.get() возвращает 2, AsyncRead функции заканчиваются, а handler как локальная переменная AsyncRead уничтожается. Но вы все еще ссылаетесь внутри замыкания на эту переменную, потому что вы захватываете ее по ссылке - это оборванная ссылка. handler необходимо переместить или скопировать в закрытие, чтобы продлить срок его службы.

rafix07 31.05.2019 16:30

Добавляю сон после result.get(), тоже краш. int val = result.get(); std::cout << std::time(nullptr) << ":after get == = " << std::endl; boost::asio::deadline_timer t(*ios, boost::posix_time::seconds(2)); t.async_wait(std::forward<CompletionToken>(token)); return val;

Zhigang Zhang 14.06.2019 10:29

Я добавляю сон после result.get(), AsyncRead завершится через 2 секунды, поэтому поток может завершиться первым, но также и сбой.

Zhigang Zhang 14.06.2019 10:35

@ZhigangZhang Пожалуйста, не могли бы вы принять мой ответ? , тогда я смогу удалить его, потому что я хотел бы это сделать. Есть много вещей с boost::asio::spawn, например, здесь играют роль сопрограммы. Вы можете запустить свое приложение под отладчиком, и вы увидите, что произойдет. Это не так просто, как вы думаете. Также нужна ссылка boost asio. Я ответил вам, что знаю, но вижу, что этого недостаточно.

rafix07 15.06.2019 10:12

Сбой происходит на *ec_=.. в обработчике класса, когда ec_ равно 0. И я использую watch point, чтобы найти, кто изменил значение: [New Thread 0x7fa915f4a700 (LWP 7970)] Thread 1 "test1" hit Hardware watchpoint 3: *0x1ed82e8 Old value = 32342816 New value = 0 0x00007fa916c69477 in _Unwind_Resume () from /lib/x86_64-linux-gnu/libgcc_s.so.1 Что такое _Unwind_Resume? Почему он меняет значение?

Zhigang Zhang 29.07.2019 11:41

`расслабиться` называется if ( from->do_unwind) throw forced_unwind(); в push_coroutine_impl::push

Zhigang Zhang 29.07.2019 14:16

Другие вопросы по теме