boost :: io_service, threads и std :: set - PullRequest
       0

boost :: io_service, threads и std :: set

2 голосов
/ 30 января 2012

Если есть что-то более сложное, чем отладка многопоточного приложения, которое пытается описать саму ошибку.

  • У меня есть два boost :: threads (приложение и отображение).
  • Оба используют один и тот же asio :: io_service для выполнения своей работы.В потоке отображения есть std :: set типа window *, который я использую, чтобы обернуть управление окнами winapi.
  • Я использую пользовательскую очередь сообщений для связи этих двух потоков.
  • Одно из этих сообщений (прекратить) используется для уведомления потока вывода о том, что он не должен "публиковать" больше методов и что он должен вызывать thread_group.remove_thread и удалять себя.имеет переменную (состояние), которая отмечает состояние потока (запущен, приостановлен, завершен).
  • Если он работает, он "отправляет" свой метод update (), который выполняет итерацию std :: set и вызывает метод обновления в каждом окне *, которое оно содержит.
  • Если оно завершается, оноочищает std :: set, удаляет себя из группы thread_group и больше не публикует работы.

Проблема: время от времени при попытке закрыть приложение запускается метод обновления потокапосле того, как поток "завершен" и очищен std :: set.Затем метод обновления пытается выполнить итерацию std :: set и происходит SIGSEGV.Это происходит только 1 раз в 10 запусков приложения, и я с трудом пытаюсь угадать, что не так.

Я постараюсь опубликовать соответствующий код, если потребуется больше, я постараюсь добавитьit.

int main(int argc, char **argv)
{
    boost::asio::io_service ios;
    boost::asio::strand     strand(ios);
    boost::thread_group     threads;
    owl::system::pump       pump;

    application app(&threads, &strand, &pump);
    owl::system::display display(&strand, &pump);

    ios.run();
    threads.join_all();

    return 0;
}
...
void display::on_terminate()
{
    close_all_windows();
}
...
void display::close_all_windows()
{
    windows.move_first();
    while (!windows.eof())
    {
        window* win = windows.value();
        win->destroy();
        delete win;
        windows.move_next();
    }
    windows.clear();
    check_no_window();
}
...
void display::on_update()
{
    if (windows.size())
    {
        windows.move_first();
        while (!windows.eof())
        {
            windows.value()->update();
            windows.move_next(); // Here happens the SIGSEGV
        }
    }
}

Отображение класса наследует подсистему класса, которая управляет выполнением потока.Это соответствующий код, включающий выполнение on_update ()

void subsystem::do_update()
{
    message* msg;

    size_t message_count = messages.size();
    for (size_t i=0; i<message_count; i++)
    {
        msg = messages[i];
        process_message(msg);
        strand->dispatch(strand->wrap(boost::bind(&message::deallocate, msg)));
    }

    switch (state)
    {
        case running:
        {
            on_update();
        }
        break;
        case paused:
        {
            // Do not update. Just check the queue and sleep
            sleep(10);
        }
        break;
        case terminated:
        {
            do_terminate();
            return;
        }
        break;
    }
        strand->post(strand->wrap(boost::bind(&subsystem::check_for_messages, this)));
}

void subsystem::check_for_messages()
{
        messages.clear();
    pump->get_messages(this, messages);
    ios->post(boost::bind(&subsystem::do_update, this));
}

SIGSEGV происходит именно при попытке увеличить итератор std :: set.

Child process PID: 2272
Program received signal SIGSEGV, Segmentation fault.
In std::_Rb_tree_increment(std::_Rb_tree_node_base const*) ()
stl_tree.h:269
...