gpt4 book ai didi

c++ - DLL中提供的ZeroMQ上下文单例,程序退出时崩溃(VS2010 win7 x64 zmq 4.0x)

转载 作者:搜寻专家 更新时间:2023-10-31 01:07:06 25 4
gpt4 key购买 nike

这是单例

#pragma once

class ContextManager {
public:
static ContextManager& Instance() {
static ContextManager instance;
return instance;
}
zmq::context_t& GetContext() { return ctx_;}
private:
zmq::context_t ctx_;
~ContextManager() {}
};

我有一个 DLL,其中包含一些有用的网络实用程序,它构建在 ZeroMQ 上并使用这个单例来不必传递上下文。

我将此 DLL 链接到运行测试套件的 EXE。这个测试套件工作,发送和接收一些消息。当程序退出时,ContextManager 析构函数崩溃并显示“断言失败:尚未执行成功的 WSASTARTUP (......\src\signaler.cpp:137)"

更多详情:

  • 应用程序是单线程的。
  • 如果我只是从 .EXE 调用 Instance.GetContext() 方法并返回(没有测试运行,不再调用 DLL 接口(interface)),那么它也会失败。
  • 如果我在 main 之前定义这个单例(因此,在 exe 内部而不使用 DLL 中的对象)那么它可以工作
  • WSastartup 只被调用一次就可以正常工作。

我不想向 DLL 客户端公开任何实现细节,因此我希望在 DLL 中包含此单例。如何实现这一目标?

最佳答案

问题是 ZMQ 使用的 WinSock 在使用前需要调用 WSAStartup()。如果您随后调用 WSAShutdown() 并使用 ZMQ,它看起来好像从未调用过 WSAStartup(),因此断言失败。在更抽象的层面上,WSAStartup() 和 WSAShutdown() 之间的时间跨度必须完全包含 ZMQ 上下文的生命周期。

C++ 中的函数级静态是按需创建的,但在 main() 返回后销毁(我相信未指定的顺序)。您没有显示对 WSAStartup() 的调用,但我猜它在 main() 内部的某个地方。类似地,对 WSAShutdown() 的调用是在 main 结束之前进行的,但这仍然会将其置于函数静态对象的破坏之前,因此会出现您所看到的问题。

两个可能的修复:

  • 使用 new 分配上下文并且永不删除它。您唯一要删除它的时间是在程序关闭时,在操作系统本身将回收程序使用的所有资源之前不久。这是一个简单而实用的修复。
  • 稍微复杂一点的是将对 WSAStartup()/WSAShutdown() 的调用绑定(bind)到单例的 ctor/dtor。在 ctor 中,启动 WinSock,然后创建上下文。在析构函数中,销毁上下文,然后释放 WinSock。

您还可以为您的 DLL 创建两个类似于 WSAStartup() 和 WSAShutdown() 的函数,但这既不方便又难看。另外,除非绝对必要,否则我至少会考虑不使用单例。强制用户以某种方式使用您的代码是一件令人讨厌的事情,但这只是我个人的看法。

关于c++ - DLL中提供的ZeroMQ上下文单例,程序退出时崩溃(VS2010 win7 x64 zmq 4.0x),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19795245/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com