boost::io_service、线程和 std::set

发布于 2024-12-29 16:41:32 字数 2844 浏览 1 评论 0原文

如果有比调试试图描述错误本身的多线程应用程序更困难的事情。

  • 我有两个 boost::threads (应用程序和显示)。
  • 两者都使用相同的 asio::io_service 来完成其工作。 显示线程有一个 window* 类型的 std::set ,它是我用来包装 winapi 窗口管理的类。
  • 我使用自定义消息队列来通信这两个线程。
  • 这些消息之一(终止)用于通知显示线程它不能再“发布”任何方法,并且它必须调用 thread_group.remove_thread 并删除自身。
  • 线程有一个变量(状态)来标记线程的状态(运行、暂停、终止)。
  • 如果它正在运行,它会“发布”它的 update() 方法,该方法会迭代 std::set 并在它包含的每个窗口* 中调用 update 方法。
  • 如果它终止,它会清除 std::set,将自身从 thread_group 中删除,并且不再发布任何工作。

问题:有时,当尝试关闭应用程序时,线程的更新方法会在线程“终止”并且 std::set 被清除后运行。然后 update 方法尝试迭代 std::set 并发生 SIGSEGV。该应用程序每运行 10 次才会出现 1 次这种情况,我很难猜测出了什么问题。

我会尝试发布相关代码,如果需要更多我会尝试添加它。

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

If there is something more difficult than debugging a multithreaded app that is trying to describe the bug itself.

  • I have two boost::threads (application and display).
  • Both use the same asio::io_service to do their work.
    The display thread has a std::set of type window* which is a class I use to wrap winapi window management.
  • I use a custom message queue to communicate these two threads.
  • One of these messages (terminate) is used to notify the display thread that it must not "post" any more methods and that it must call thread_group.remove_thread and remove itself.
  • The thread has a variable (state) that flags the state of the thread (running, paused, terminated).
  • If it is running it "posts" it's update() method that iterates an std::set and calls the update method in each window* it contains.
  • If it is terminated, it clears the std::set, removes itself from the thread_group and doesn't post any more work.

The problem: Once a while, when trying to close the app, the thread's update method gets ran after the thread got "terminated" and the std::set got cleared. Then the update method tries to iterate the std::set and a SIGSEGV takes place. This only happens 1 every 10 runs of the application and I'm having a hard time trying to guess what's wrong.

I'll try to post the relevant code, if more is needed I'll try to add 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
        }
    }
}

The class display inherits the class subsystem that manages thread execution. This is the relevant code involving the execution of 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));
}

The SIGSEGV occurs exactly when trying to increment the std::set iterator.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文