Почему я не могу использовать два таймера для одного asio io_service? - PullRequest
1 голос
/ 11 июня 2019

Я новичок в asio и пытаюсь изменить некоторые примеры для своих целей.Одной из мыслей было бы запустить несколько таймеров и посмотреть, изменится ли поведение, если я запускаю io_service.run () в нескольких потоках.Тем не менее, я даже не понимаю, как несколько таймеров вызывают ошибку сегментации, которую я не понимаю.

Мой минимальный рабочий пример такой:

#include <iostream>
#include <asio.hpp>

class printer {
public:
    asio::steady_timer timer;
    asio::io_service &io_service;
    int count;

    printer(asio::io_service &io_service) : io_service(io_service), timer(io_service, asio::chrono::milliseconds(10)) , count(0) {
        timer.async_wait(std::bind(&printer::timer_func, this));
    }

    void timer_func() {
        std::cout << "count " << ++count << ", on thread " << std::this_thread::get_id() << std::endl;
        if (count < 5)
        {
            timer.expires_at(timer.expiry() + asio::chrono::milliseconds(10));
            timer.async_wait(std::bind(&printer::timer_func, this));
        }
    }
};

int main()
{
    const int NUM_PRINTERS = 2;
    asio::io_service io;

    std::vector<printer> work_timers;
    for (int i = 0; i < NUM_PRINTERS; ++i) {
        work_timers.emplace_back(io);
    }

    io.run();

    std::cout << "broker completed.\n";

    return 0;
}

Для NUM_PRINTERS = 1,это успешно выполняется:

count 1, on thread 139779481040704
count 2, on thread 139779481040704
count 3, on thread 139779481040704
count 4, on thread 139779481040704
count 5, on thread 139779481040704
broker completed.

Однако для NUM_PRINTERS> 1 я получаю ошибку сегментации:

count 1, on thread 140493102753600

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

С моей точки зрения, я понятия не имею, как это может произойти.Оба объекта принтера имеют свои собственные переменные, и я не понимаю, откуда это происходит.Почему возникает ошибка сегментации?

1 Ответ

2 голосов
/ 11 июня 2019

В конструкторе вы привязываете вызываемое к this. Однако экземпляры printer могут перемещаться при перераспределении work_timers после вставки, в результате чего зарегистрированные обратные вызовы к steady_timer будут недействительными. Простое решение - позвонить заранее work_timers.reserve(NUM_PRINTERS). Тогда это работает (исправьте предупреждения).

Помимо неопределенного поведения от аннулирования указателя, steady_timer s также отменяется при перемещении , поэтому попытка вызова обработчика была вызвана ошибкой. Вы действительно должны убедиться, что таймеры и их обратные вызовы переживают задержку. Если вам нужен более гибкий класс printer, выделите эти внутренние компоненты динамически.

...