在win_mutex锁中boost :: asio :: io_service崩溃 [英] boost::asio::io_service crash in win_mutex lock

查看:129
本文介绍了在win_mutex锁中boost :: asio :: io_service崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been having a problem with boost::asio where timer and/or sockets created using a global io_service instance crash during construction. The system where the crash occurs is as follows:

  • Windows 7

  • Windows 7

用于Windows桌面的Visual Studio 2013 Express; v 12.0.31101.00更新4

Visual Studio 2013 Express for Windows Desktop; v 12.0.31101.00 Update 4

Boost 1.57,动态链接,使用多线程进行编译,例如boost_thread-vc120-mt-gd-1_57.dll

Boost 1.57, dynamically linked, compiled with multithreading as, e.g. boost_thread-vc120-mt-gd-1_57.dll

我已经可以使用以下简化代码来复制该问题:

I've been able to replicate the issue in the following simplified code:

//文件global_io_service.h

// file 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

// File 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;
}

//FILE main.cpp

// FILE 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()第51行

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)第47行

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)第477行

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)第79行

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)第69行

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)第78行

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)第81行

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)第123行

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>>()第49行

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)第34行

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)第91行

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_line) 151

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)第16行C ++

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

这是我所学到的:

  • 在带有Boost 1.54的Ubuntu 14.04,Ubuntu 14.10或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对象的正确构造.

希望我今天过得很糟糕,正在调用未定义的行为. 否则,我想了解为什么会这样?预先感谢.

Hopefully, I'm having a bad day and invoking undefined behavior. Otherwise, I'd like to understand why this is happening? Thanks in advance.

推荐答案

问题是ASIO根据BOOST_ASIO_HAS_IOCP是否由boost/asio/detail/config.hpp定义来选择Windows上的io_service实现.如果定义,它将使用win_iocp_io_service.如果没有,它将使用task_io_service-参见boost/asio/io_service.hpp.如果跨翻译单元的选择不同,则最终将io_service初始化为一个,然后将其用作另一个.它们在微妙的方面有所不同,例如初始化了哪些互斥锁,因此此问题可能会因使用未初始化的互斥锁而崩溃.

The problem is that ASIO selects its io_service implementation on Windows by whether or not BOOST_ASIO_HAS_IOCP gets defined by boost/asio/detail/config.hpp. If defined, it will use the win_iocp_io_service. If not, it will use the task_io_service - see boost/asio/io_service.hpp. If this selection is different across translation units, you will end up initializing the io_service as one and using it as another. They differ in subtle ways, e.g. what mutexes are initialized, so this problem can manifest as a crash due to using an uninitialized mutex.

关于选择BOOST_ASIO_HAS_IOCP的内容,让我们看一下config.hpp:

As for what selects BOOST_ASIO_HAS_IOCP, let's look at 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

In this case, the controversial macro is _WIN32_WINNT, which appears to be getting defined by WinSock2.h in your project. Because it's defined in main.cpp, but not defined in global_io_service.cpp, you're initializing io_service to use task_io_service and calling it as if it used win_iocp_io_service

要解决此问题,请在编译器定义或全局头文件中适当定义_WIN32_WINNT,或者仅通过定义BOOST_ASIO_DISABLE_IOCP(再次,全局)将IOCP反应器完全关闭.

To resolve the problem, either appropriately define _WIN32_WINNT in your compiler definitions or global header file, or just turn the IOCP reactor off altogether by defining BOOST_ASIO_DISABLE_IOCP (again, globally).

这篇关于在win_mutex锁中boost :: asio :: io_service崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆