boost::io_service、线程和 std::set
如果有比调试试图描述错误本身的多线程应用程序更困难的事情。
- 我有两个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论