boost::asio::io_service 在 win_mutex 锁中崩溃

2024-04-05

我一直遇到 boost::asio 问题,其中使用全局 io_service 实例创建的计时器和/或套接字在构造过程中崩溃。发生崩溃的系统如下:

  • Windows 7的

  • 适用于 Windows 桌面的 Visual Studio 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;
}

// 文件主.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() 第 51 行

test_io_service.exe!boost::asio::detail::scoped_lock::scoped_lock(boost::asio::detail::win_mutex & m) 第 47 行

test_io_service.exe!boost::asio::detail::win_iocp_io_service::do_add_timer_queue(boost::asio::detail::timer_queue_base & 队列) 第 477 行

test_io_service.exe!boost::asio::detail::win_iocp_io_service::add_timer_queue >(boost::asio::detail::timer_queue > & 队列) 第 79 行

test_io_service.exe!boost::asio::detail::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) 第 69 行

test_io_service.exe!boost::asio::deadline_timer_service >::deadline_timer_service >(boost::asio::io_service & io_service) 第 78 行

test_io_service.exe!boost::asio::detail::service_registry::create >>(boost::asio::io_service & 所有者) 第 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 &) * 工厂) 第 123 行

test_io_service.exe!boost::asio::detail::service_registry::use_service >>() 第 49 行

test_io_service.exe!boost::asio::use_service >>(boost::asio::io_service & ios) 第 34 行

test_io_service.exe!boost::asio::basic_io_object >,0>::basic_io_object >,0>(boost::asio::io_service & io_service) 第 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) 第 151 行

test_io_service.exe!main(int argc, char * * argv) 第 16 行 C++

这是我学到的:

  • 在 Ubuntu 14.04、Ubuntu 14.10 或带有 boost 1.54 的 Red Hat 6.5 中不会出现此问题。
  • 该问题似乎与 Winsock2 的包含顺序有关。例如,与 global_io_service.h 交换包含顺序可以消除崩溃。
  • 该问题似乎与 global_timer_io_service 的外部链接有关。将 global_timer_io_service 的定义移动到 main.cpp 中可以消除崩溃。
  • 我发现有关 io_service 内部关键部分发生类似崩溃的报告。这些问题主要与传递给计时器/套接字构造函数的 io_service 对象的生命周期有关。就我而言,我认为我正在使用的 io_service 已经在输入 main 之前构建好了。
  • 我的直觉告诉我,存在竞争条件(也许是 WinSock2 中的某些全局状态设置?),它阻止了 io_service 对象的正确构造。

希望我今天过得很糟糕并引发了未定义的行为。 否则,我想了解为什么会发生这种情况?提前致谢。


问题在于 ASIO 在 Windows 上选择其 io_service 实现是通过是否BOOST_ASIO_HAS_IOCP定义为boost/asio/detail/config.hpp。如果定义的话,它将使用win_iocp_io_service。如果没有,它将使用task_io_service - see 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在编译器定义或全局头文件中,或者通过定义完全关闭 IOCP 反应器BOOST_ASIO_DISABLE_IOCP(再次,全球)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

boost::asio::io_service 在 win_mutex 锁中崩溃 的相关文章

随机推荐