boost::asio::io_service 在 win_mutex 锁中崩溃
boost::asio::io_service crash in win_mutex lock
我遇到了 boost::asio 问题,其中使用全局 io_service 实例创建的计时器 and/or 套接字在构造期间崩溃。发生崩溃的系统如下:
Windows 7
Visual Studio Windows 桌面版 2013 Express; v 12.0.31101.00 更新 4
Boost 1.57,动态链接,使用多线程编译,例如boost_thread-vc120-mt-gd-1_57.dll
我已经能够在以下简化代码中重现该问题:
// 文件 global_io_service.h
#ifndef INCLUDED_GLOBAL_IO_SERVICE_H
#define INCLUDED_GLOBAL_IO_SERVICE_H
#include <boost/asio/io_service.hpp>
#include <iostream>
#include <string>
namespace foo{
extern boost::asio::io_service test_io_service;
class foo_base_io_service{
public:
foo_base_io_service(const std::string& name)
: d_who_am_i(name)
{
std::cout << "constructing copy " << ++foo_base_io_service::num_instances << "my name is " << d_who_am_i << std::endl;
}
boost::asio::io_service& get_ref()
{
std::cout << "class requested copy of " << d_who_am_i << std::endl;
return d_ios;
}
~foo_base_io_service()
{
std::cout << "Someone 86'd the base_io_service..." << std::endl;
}
private:
// this class is not copyable
foo_base_io_service(const foo_base_io_service&);
foo_base_io_service& operator=(const foo_base_io_service&);
std::string d_who_am_i;
static int num_instances;
boost::asio::io_service d_ios;
};
extern foo_base_io_service global_timer_io_service;
} // namespace foo
#endif
// 文件 global_io_service.cpp
#include "global_io_service.h"
namespace foo{
boost::asio::io_service test_io_service;
foo_base_io_service global_timer_io_service("FOO_TIMER_SERVICE");
// static initialization
int foo_base_io_service::num_instances = 0;
}
// 文件 main.cpp
#include <WinSock2.h>
#include "global_io_service.h"
#include <boost/asio/deadline_timer.hpp>
int main(int argc, char *argv[])
{
// also causes crash
boost::asio::deadline_timer crash_timer2(foo::test_io_service);
// causes crash
boost::asio::deadline_timer crash_timer(foo::global_timer_io_service.get_ref());
return 0 ;
}
这里是崩溃的回溯:
test_io_service.exe!boost::asio::detail::win_mutex::lock() Line 51
test_io_service.exe!boost::asio::detail::scoped_lock::scoped_lock(boost::asio::detail::win_mutex & m) Line 47
test_io_service.exe!boost::asio::detail::win_iocp_io_service::do_add_timer_queue(boost::asio::detail::timer_queue_base & queue) Line 477
test_io_service.exe!boost::asio::detail::win_iocp_io_service::add_timer_queue >(boost::asio::detail::timer_queue > & queue) Line 79
test_io_service.exe!boost::asio::detail::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) Line 69
test_io_service.exe!boost::asio::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) Line 78
test_io_service.exe!boost::asio::detail::service_registry::create > >(boost::asio::io_service & owner) Line 81
test_io_service.exe!boost::asio::detail::service_registry::do_use_service(const boost::asio::io_service::service::key & key, boost::asio::io_service::service * (boost::asio::io_service &) * factory) Line 123
test_io_service.exe!boost::asio::detail::service_registry::use_service > >() Line 49
test_io_service.exe!boost::asio::use_service > >(boost::asio::io_service & ios) Line 34
test_io_service.exe!boost::asio::basic_io_object >,0>::basic_io_object >,0>(boost::asio::io_service & io_service) Line 91
test_io_service.exe!boost::asio::basic_deadline_timer,boost::asio::deadline_timer_service > >::basic_deadline_timer,boost::asio::deadline_timer_service > >(boost::asio::io_service & io_service) Line 151
test_io_service.exe!main(int argc, char * * argv) Line 16 C++
这是我学到的:
- 此问题不会出现在 Ubuntu 14.04、Ubuntu 14.10 或 Red Hat 6.5 with boost 1.54 中。
- 出现的问题与包含 Winsock2 的顺序有关。例如,将包含顺序与 global_io_service.h 交换可以消除崩溃。
- 出现的问题与 global_timer_io_service 的外部链接有关。将 global_timer_io_service 的定义移动到 main.cpp 消除了崩溃。
- 我发现了在 io_service 内部关键部分发生类似崩溃的报告。这些问题主要与传递给 timer/socket 构造函数的 io_service 对象的生命周期有关。就我而言,我认为我正在使用的 io_service 在输入 main 之前已经构建。
- 我的直觉说存在竞争条件(也许是 WinSock2 中的某些全局状态设置?)阻止 io_service 对象的正确构造。
希望我今天过得很糟糕,并且调用了未定义的行为。
否则,我想了解为什么会这样?提前致谢。
问题是 yoor ioservice 的生命周期。你把它从物体中抓出来。
ioservice 的寿命必须比所有服务都长。
在这个例子中
http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/tutorial/tuttimer2.html
ioservice 的寿命比截止时间计时器长。
编辑:这是鲍里斯·谢林 (boris schäling) 的德语在线图书
http://dieboostcppbibliotheken.de/boost.asio-ioservices-und-objekte
问题在于 ASIO 选择其 io_service 在 Windows 上的实现是根据 BOOST_ASIO_HAS_IOCP
是否由 boost/asio/detail/config.hpp
定义。如果已定义,它将使用 win_iocp_io_service
。如果不是,它将使用 task_io_service
- 请参阅 boost/asio/io_service.hpp
。如果此选择在翻译单元中不同,您最终会将 io_service 初始化为一个并将其用作另一个。它们在细微的方面有所不同,例如初始化了哪些互斥量,因此此问题可能表现为由于使用未初始化的互斥量而导致的崩溃。
至于什么选择BOOST_ASIO_HAS_IOCP
,我们看config.hpp
:
#if !defined(BOOST_ASIO_HAS_IOCP)
# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
# if !defined(UNDER_CE)
# if !defined(BOOST_ASIO_DISABLE_IOCP)
# define BOOST_ASIO_HAS_IOCP 1
# endif // !defined(BOOST_ASIO_DISABLE_IOCP)
# endif // !defined(UNDER_CE)
# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
#endif // !defined(BOOST_ASIO_HAS_IOCP)
在这种情况下,有争议的宏是 _WIN32_WINNT
,它似乎是由您的项目中的 WinSock2.h
定义的。因为它在 main.cpp
中定义,但未在 global_io_service.cpp
中定义,所以 您正在初始化 io_service 以使用 task_io_service
并像使用 win_iocp_io_service
要解决此问题,请在编译器定义或全局头文件中适当地定义 _WIN32_WINNT
,或者通过定义 BOOST_ASIO_DISABLE_IOCP
(同样是全局)来完全关闭 IOCP 反应器。
在我的例子中,我在 class header 中的 io_service
之前定义了 deadline_timer
导致了这个问题。
我遇到了 boost::asio 问题,其中使用全局 io_service 实例创建的计时器 and/or 套接字在构造期间崩溃。发生崩溃的系统如下:
Windows 7
Visual Studio Windows 桌面版 2013 Express; v 12.0.31101.00 更新 4
Boost 1.57,动态链接,使用多线程编译,例如boost_thread-vc120-mt-gd-1_57.dll
我已经能够在以下简化代码中重现该问题:
// 文件 global_io_service.h
#ifndef INCLUDED_GLOBAL_IO_SERVICE_H
#define INCLUDED_GLOBAL_IO_SERVICE_H
#include <boost/asio/io_service.hpp>
#include <iostream>
#include <string>
namespace foo{
extern boost::asio::io_service test_io_service;
class foo_base_io_service{
public:
foo_base_io_service(const std::string& name)
: d_who_am_i(name)
{
std::cout << "constructing copy " << ++foo_base_io_service::num_instances << "my name is " << d_who_am_i << std::endl;
}
boost::asio::io_service& get_ref()
{
std::cout << "class requested copy of " << d_who_am_i << std::endl;
return d_ios;
}
~foo_base_io_service()
{
std::cout << "Someone 86'd the base_io_service..." << std::endl;
}
private:
// this class is not copyable
foo_base_io_service(const foo_base_io_service&);
foo_base_io_service& operator=(const foo_base_io_service&);
std::string d_who_am_i;
static int num_instances;
boost::asio::io_service d_ios;
};
extern foo_base_io_service global_timer_io_service;
} // namespace foo
#endif
// 文件 global_io_service.cpp
#include "global_io_service.h"
namespace foo{
boost::asio::io_service test_io_service;
foo_base_io_service global_timer_io_service("FOO_TIMER_SERVICE");
// static initialization
int foo_base_io_service::num_instances = 0;
}
// 文件 main.cpp
#include <WinSock2.h>
#include "global_io_service.h"
#include <boost/asio/deadline_timer.hpp>
int main(int argc, char *argv[])
{
// also causes crash
boost::asio::deadline_timer crash_timer2(foo::test_io_service);
// causes crash
boost::asio::deadline_timer crash_timer(foo::global_timer_io_service.get_ref());
return 0 ;
}
这里是崩溃的回溯:
test_io_service.exe!boost::asio::detail::win_mutex::lock() Line 51
test_io_service.exe!boost::asio::detail::scoped_lock::scoped_lock(boost::asio::detail::win_mutex & m) Line 47
test_io_service.exe!boost::asio::detail::win_iocp_io_service::do_add_timer_queue(boost::asio::detail::timer_queue_base & queue) Line 477
test_io_service.exe!boost::asio::detail::win_iocp_io_service::add_timer_queue >(boost::asio::detail::timer_queue > & queue) Line 79
test_io_service.exe!boost::asio::detail::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) Line 69
test_io_service.exe!boost::asio::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) Line 78
test_io_service.exe!boost::asio::detail::service_registry::create > >(boost::asio::io_service & owner) Line 81
test_io_service.exe!boost::asio::detail::service_registry::do_use_service(const boost::asio::io_service::service::key & key, boost::asio::io_service::service * (boost::asio::io_service &) * factory) Line 123
test_io_service.exe!boost::asio::detail::service_registry::use_service > >() Line 49
test_io_service.exe!boost::asio::use_service > >(boost::asio::io_service & ios) Line 34
test_io_service.exe!boost::asio::basic_io_object >,0>::basic_io_object >,0>(boost::asio::io_service & io_service) Line 91
test_io_service.exe!boost::asio::basic_deadline_timer,boost::asio::deadline_timer_service > >::basic_deadline_timer,boost::asio::deadline_timer_service > >(boost::asio::io_service & io_service) Line 151
test_io_service.exe!main(int argc, char * * argv) Line 16 C++
这是我学到的:
- 此问题不会出现在 Ubuntu 14.04、Ubuntu 14.10 或 Red Hat 6.5 with boost 1.54 中。
- 出现的问题与包含 Winsock2 的顺序有关。例如,将包含顺序与 global_io_service.h 交换可以消除崩溃。
- 出现的问题与 global_timer_io_service 的外部链接有关。将 global_timer_io_service 的定义移动到 main.cpp 消除了崩溃。
- 我发现了在 io_service 内部关键部分发生类似崩溃的报告。这些问题主要与传递给 timer/socket 构造函数的 io_service 对象的生命周期有关。就我而言,我认为我正在使用的 io_service 在输入 main 之前已经构建。
- 我的直觉说存在竞争条件(也许是 WinSock2 中的某些全局状态设置?)阻止 io_service 对象的正确构造。
希望我今天过得很糟糕,并且调用了未定义的行为。 否则,我想了解为什么会这样?提前致谢。
问题是 yoor ioservice 的生命周期。你把它从物体中抓出来。
ioservice 的寿命必须比所有服务都长。
在这个例子中 http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/tutorial/tuttimer2.html ioservice 的寿命比截止时间计时器长。
编辑:这是鲍里斯·谢林 (boris schäling) 的德语在线图书 http://dieboostcppbibliotheken.de/boost.asio-ioservices-und-objekte
问题在于 ASIO 选择其 io_service 在 Windows 上的实现是根据 BOOST_ASIO_HAS_IOCP
是否由 boost/asio/detail/config.hpp
定义。如果已定义,它将使用 win_iocp_io_service
。如果不是,它将使用 task_io_service
- 请参阅 boost/asio/io_service.hpp
。如果此选择在翻译单元中不同,您最终会将 io_service 初始化为一个并将其用作另一个。它们在细微的方面有所不同,例如初始化了哪些互斥量,因此此问题可能表现为由于使用未初始化的互斥量而导致的崩溃。
至于什么选择BOOST_ASIO_HAS_IOCP
,我们看config.hpp
:
#if !defined(BOOST_ASIO_HAS_IOCP)
# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
# if !defined(UNDER_CE)
# if !defined(BOOST_ASIO_DISABLE_IOCP)
# define BOOST_ASIO_HAS_IOCP 1
# endif // !defined(BOOST_ASIO_DISABLE_IOCP)
# endif // !defined(UNDER_CE)
# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
#endif // !defined(BOOST_ASIO_HAS_IOCP)
在这种情况下,有争议的宏是 _WIN32_WINNT
,它似乎是由您的项目中的 WinSock2.h
定义的。因为它在 main.cpp
中定义,但未在 global_io_service.cpp
中定义,所以 您正在初始化 io_service 以使用 task_io_service
并像使用 win_iocp_io_service
要解决此问题,请在编译器定义或全局头文件中适当地定义 _WIN32_WINNT
,或者通过定义 BOOST_ASIO_DISABLE_IOCP
(同样是全局)来完全关闭 IOCP 反应器。
在我的例子中,我在 class header 中的 io_service
之前定义了 deadline_timer
导致了这个问题。