首页 > 编程语言 >使用 zeromq与cppzmq 程序退出遇到的坑

使用 zeromq与cppzmq 程序退出遇到的坑

时间:2023-03-21 11:58:07浏览次数:34  
标签:src socket 静态 程序 cppzmq static 进程 zeromq zmq

在使用zeromq 退出的时候还遇到一点坑,对于服务deaman(守护进程)化的进程可能会遇到这个问题。

现象:

这个问题导致的现象是服务一旦关闭(stop),就会 core dump,core dump 的信息如下。意思大概是使用了无效的描述符。

img

(gdb) bt
#0 0x00007f522e2le387 in raise () from /lib64/libec.so.6
#1 0x00007f522e21fbb8 in abort () from /lib64/libec.so.6
#2 0x00000000004d5909 in zmq::zmq_abort (errmsg_errmsg_@entry=0x7f522e37025f "Bad file descriptor") at src/err.cpp :88
#3 0x00000000004d5242 in zmq::epoll_t::add_fd_(this=0x1b25520, fd_efd_@entry=15, events_events_@entry=0x1b28580) at src/epoll.cpp:100
#4 0x00000000004e42e2 in zmq::socket_base_t::start_reapiing (this=0x1b28140, poller_=<optimized out>) at src/socket_base.cpp:1465
#5 0x000000000004ela63 in zmq::reaper_t::process_reap (this=0xlb21580, socket_=<optimized out>) at src/reapercpp:133
#6 0x000000000004ele7c in zmq::reaper_t::in_event (this=0x21b21580) at src/reaper.cpp:104
#7 0x00000000004d508e in zmq::epoll_t::loop (this=0x1b255520) at src/epoll.cpp:206
#8 0x00000000004f0d45 in thread_routine (arg_=0x1b255778) at src/thread.cpp:257
#9 0x00007f522f23dea5 in start_thread () from /lib64/libpthread.so.0
#10 0x00007f522e2e6b0d in clone () from /lib64/libc.so.6

产生的原因:

我们服务的 Server 是个 static Instance 单例,在 Server 里默认分配内存的方式声明了 zeromq 的 ContextsocketServer 单例创建的时候,就会创建好 Context 和 socket。


class Server
{
	....
  private:
	  zmq::context_t m_context;
    zmq::socket_t  m_socket;
}

在启动服务后,会判断是否需要守护化(daemon化),如果需要,就会 fork 进程并创建守护进程,主进程退出。

正是主进程退出时没有调用 Context 的销毁函数,导致子进程退出时,虽然处理了 Context 的销毁,但是主进程创建的 Context 却没有调用销毁函数,导致和 zeromq 内部线程还在访问失效的描述符,从而出现了 core dump。这里需要解释一下,在 fork 时,子进程也会拷贝父进程的 static 数据。

下面是关于 fork 后父进程和子进程 static 内存数据的介绍:

在 fork 函数调用时,父进程的内存会被复制到子进程中,包括 static 数据的内存。这意味着子进程也会拥有与父进程相同的 static 数据,但是它们是相互独立的。如果在父进程或子进程中修改了 static 数据,则不会影响另一个进程中的 static 数据。

补充一段static类析构调用时机的介绍:

对于在 C++ 中声明为静态变量的类对象,其析构函数会在程序结束时被调用。具体来说,静态对象的析构函数会在程序退出 main 函数后,动态库被卸载之前,以及进程终止时被调用。

静态对象的析构顺序和构造顺序相反。也就是说,先构造的静态对象后被析构,后构造的静态对象先被析构。这一点需要注意,因为不同的静态对象之间可能存在相互依赖的关系,因此析构顺序可能会对程序的正确性产生影响。

需要注意的是,如果静态对象是在动态链接库中定义的,则其析构函数会在动态链接库被卸载之前被调用。因此,如果静态对象依赖于动态链接库中的其他对象或者库资源,需要注意析构顺序的问题,避免出现资源泄漏或者悬挂指针等问题。

另外,对于静态对象的构造函数和析构函数,需要确保它们不会产生任何异常,否则可能会导致静态对象无法正确地被构造或析构,从而产生未定义行为。

解决方法:

m_contextm_socket 声明为指针类型,在守护化后的 Init 调用中进行初始化。

  private:
	  zmq::context_t * m_context;
    zmq::socket_t  * m_socket;

这也给我们一些启示,对于类成员是第三方类,最好声明为指针,在初始化函数里调用初始化。

标签:src,socket,静态,程序,cppzmq,static,进程,zeromq,zmq
From: https://www.cnblogs.com/listenwind666/p/17239467.html

相关文章

  • 微信小程序封装API接口(2)
    先建一个api文件夹(叫什么都可以,但是为了规范化),在下面新建文件request.js// ----http----// api URLconst apiUrl = "https://接口地址:端口";// 公共的请求地址......
  • Python——程序中的循环(五)
    1.第一个循环-while#coding=utf-8#while循环i=1whilei<5:#永远为Trueprint(i)#这里需要一个控制方向i=i+1print("计算后此时i......
  • 【Unity3D】协同程序
    1简介​1)协程概念​协同程序(Coroutine)简称协程,是伴随主线程一起运行的程序片段,是一个能够暂停执行的函数,用于解决程序并行问题。协程是C#中的概念,由于Unity3......
  • uni APP 怎么打开支付宝小程序
    uni APP怎么打开支付宝小程序,直接上代码//#ifdefAPP-PLUSuni.getSystemInfo({success(res){if(res.platform=='android'){......
  • Linux启动Java程序jar包Shell脚本
    手动方式启动和终止java程序启动java程序jar:nohupjava-jarXXX.jar查看程序占用pid:ps-ef|grepXXX.jar或jpsjps是jdk提供的一个查看当前java进程的小工具,查询Lin......
  • Java程序创建 windows 服务 .exe 创建 windows服务
    java-jarxx.jar命令启动Java程序,这个方式主要有两个缺点,一是在任务栏会有黑图标,而且没有名字,在有几个黑图标的情况下,不知道哪个服务是开启的;缺点2:这种启动方式,如果一定......
  • GPSSworld仿真(一):程序题——单窗口排队系统
    3.3一个仓库共存放了2000吨货物,货物以三种规模出库,少量(10吨),中等(20吨),大量(50吨),分别以10±5分,15分,30±10分的速率出库。如果没有货位达到的情况下,一个仓库能维持供货多少时......
  • 【C/调试实用技巧】—作为程序员应如何面对并尝试解决Bug?
    @​​TOC​前言我相信大家在写代码,或者刷题时,不可能每一次都是一次就能写出完美的不出错误的代码,如果真实这样的话,恭喜你,你是一个天才,并不需要进行本篇文章的学习,此文章是我......
  • 数字化转型必备:营销模板与小程序容器技术助力企业数字化营销
    在数字化时代,营销活动的方式也随之改变。 营销模板和小程序容器是两种现代化的数字营销技术。营销模板是一种可以快速创建专业级营销材料的软件工具,而小程序容器技术......
  • 组装式应用新趋势:小程序技术科提高软件开发效率
    随着移动互联网的普及,移动应用的需求逐渐增加,而小程序作为一种轻量级的应用形式,逐渐成为了移动应用开发的一种趋势。小程序具有轻量化、低门槛、易于传播等特点,越来越多的......