【问题标题】:ZeroMQ context singleton, provided in a DLL, crashes when program exits (VS2010 win7 x64 zmq 4.0x)ZeroMQ上下文单例,在DLL中提供,程序退出时崩溃(VS2010 win7 x64 zmq 4.0x)
【发布时间】:2013-11-15 00:35:37
【问题描述】:

这是单身

#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 接口),那么它也会失败。
  • 如果我在 main 之前定义这个单例(因此,在 exe 内部而不使用 DLL 中的对象),那么 它可以工作。
  • WSastartup 只需调用一次即可。

我不想向 DLL 客户端公开任何实现细节,所以我希望在 DLL 中包含这个单例。怎么可能做到这一点?

【问题讨论】:

  • 如果我在其他类中进行 context_t 保留和销毁并且它没有暴露给 .EXE,那么它工作正常......但我不知道为什么我不能使用单例暴露。

标签: c++ zeromq


【解决方案1】:

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

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

两个可能的修复:

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

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

【讨论】:

  • 我想我不清楚对 WSAStartup 的调用。当单例实际实例化时(即第一次调用它时)调用它。我的意思是,我没有明确调用 WSAStartup。我会尝试 -never-delete-context 的东西......它应该可以工作
  • 2022 - 第一个可能的答案没有解决问题:(
  • 嗯,有什么问题吗?你明白了吗?你有minimal reproducible example 吗?这与上述@MHRahman 有何不同?
  • 是的,我明白你的回答。首先,感谢您提供我以前真的不知道的详细信息。实际上我正在构建类似的代码。所以 ZeroMQ zmq::socket_t 和 zmq::context_t 位于静态类中。在程序关闭之前它工作正常。使用VS 2019,该错误是程序调用dtor时引起的。错误在 void close() 和 zmq_close(_handle) link 内部。对不起,我的解释很糟糕。看来我得自己想办法了
  • 这些“静态类”可能是单例。更糟糕的是,它们依赖于其他单例。我认为可能的原因是一些代码已经关闭(调用析构函数),而还有一些其他单例(可能隐藏在 ZMQ 中)。简而言之,你有一个依赖问题。也就是说,单例正是因为这个原因而不好,而且它们也使测试变得困难。
猜你喜欢
  • 2012-08-15
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多