exit(3)在Linux C++中挂起
exit(3) hangs in Linux C++
我有一个小型C++程序,它可以ping网络上的其他机器,并通过另一个网络发送状态信息。该程序作为守护进程运行,因此启动进程派生出一个子进程,然后调用exit
。该程序经过交叉编译,可在两种不同的体系结构上运行:x86和ARM。GCC版本分别为4.4和3.5。我可以在x86上编译和运行该程序,它运行得非常完美。但是,当我在ARM上运行程序时,每当我调用exit
时,它都会挂起,而不仅仅是在fork
之后。我没有在atexit
或on_exit
注册的功能。以下是我的产品:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
#include <vector>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "telnet_client.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <syslog.h>
#include <customlib1.h>
#include <customlib2.h>
以下是我的GCC命令:
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP=""`date '+%F %T'`"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c can_wifid.cpp -o can_wifid.o
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP=""`date '+%F %T'`"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c telnet_client.cpp -o telnet_client.o
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP=""`date '+%F %T'`"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src can_wifid.o telnet_client.o -L/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/lib -L../lib_embest_arm -L../lib_rms_embest_arm -Wl,-Bdynamic -lutilities -lboost_system -lboost_thread -lcanprovider -lembestcan -o can_wifid
即使只是用getopt
解析我的命令行参数,然后在版本消息后调用exit
也会导致这个问题(在我的程序中最简单的情况)。有人经历过exit
挂着的这种情况吗?
编辑:添加了主要功能第一部分的代码:
struct canwifid_options
{
public:
bool daemon_mode;
int verbosity;
canwifid_options()
{
this->daemon_mode = false;
this->verbosity = LOG_NOTICE;
}
};
static canwifid_options options;
int main(int argc, char * argv[])
{
int LoggingOptions = LOG_CONS|LOG_NDELAY|LOG_PID;
pid_t Pid;
ParseCommandLine(argc, argv);
if (!options.daemon_mode)
{
LoggingOptions |= LOG_PERROR;
}
openlog("can_wifid", LoggingOptions, LOG_USER);
setlogmask(LOG_UPTO(options.verbosity));
if (options.daemon_mode)
{
Pid = fork();
if (Pid < 0)
{
// couldn't fork off and create a child process
// log it, %m is a special syslog flag
syslog(LOG_CRIT, "Unable to create daemon [Error: %m]");
exit(ESRCH);
}
else if (Pid > 0)
{
// we're the parent, so we're done and out of here
exit(EXIT_SUCCESS);
}
else
{
// we're the child, take control of the session.
setsid();
// change to the root directory so we don't retain unnecessary control
// of any mounted volumes
chdir("/");
// clear our file mode creation mask
umask(0000);
}
}
else
{
// get our process ID
Pid = getpid();
}
syslog(LOG_INFO, "Running as %s", options.daemon_mode ? "daemon" : "standalone");
// Network code here, snipped for clarity
}
还有ParseCommandLine函数:
static void ParseCommandLine(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "dhqvDV?")) > 0)
{
switch (c)
{
case 'd':
options.daemon_mode = true;
break;
case 'V':
VersionMessage(argv);
exit(EXIT_SUCCESS);
break;
case 'q':
options.verbosity = LOG_WARNING;
break;
case 'v':
options.verbosity = LOG_INFO;
break;
case 'D':
options.verbosity = LOG_DEBUG;
break;
case 'h':
case '?':
default:
HelpMessage(argv);
exit(EXIT_SUCCESS);
break;
}
}
return; //done
}
我曾经遇到的一个问题是,调用exit
尝试退出并调用全局析构函数,而不尝试展开堆栈或调用堆栈上本地对象的任何析构函数。如果您有全局析构函数可能需要的任何类型的锁,这可以很容易地表现出来。例如,这个程序在退出时(实际上在全局dtor中)死锁:
#include <iostream>
#include <mutex>
std::mutex lock;
class A {
public:
A() {
std::lock_guard<std::mutex> acquire(lock);
std::cout << "ctor A" << std::endl;
}
~A() {
std::lock_guard<std::mutex> acquire(lock);
std::cout << "dtor A" << std::endl;
}
};
A a;
int main()
{
std::lock_guard<std::mutex> acquire(lock);
exit(0);
}
现在,您的问题可能完全不同,但它很有可能与全局析构函数中的某个错误有关,因为堆栈上的某个对象没有正确销毁。
如果您想在正确展开堆栈时退出(这是RAII结构化代码所必需的),则不能调用exit。相反,您需要抛出一个异常,该异常(仅)在main中被捕获并导致main返回。
相关文章:
- 挂起和取消挂起一个文件DLL
- 如何防止C++遗留代码中的挂起指针
- 为什么所有C++编译器都会崩溃或挂起此代码
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- 构建挂起,即使是适度的文件大小
- 循环挂起迭代的 std::擦除 on std::list
- Poco::Net::FTPClientSession 在 open() 方法上挂起 129 秒,如果 ftp 主机不存
- Node.js fs.open() 在尝试打开 4 个以上的命名管道 (FIFO) 后挂起
- 从不同进程中的另一个线程挂起/恢复线程或进程
- Boost (Beast) websocket:同步写入挂起
- 为什么析构函数挂起
- 使用互斥会挂起程序
- 在C++和 Python 程序中使用命名管道的 IPC 挂起
- 设置变量时C++程序挂起
- 第一次尝试使用new动态创建结构数组,程序挂起没有错误
- 从stdin读取时子进程挂起(fork/dup2竞争条件)
- 有时ShowWindow从不调用OnShowWindow,主应用程序挂起
- 如何防止GUI挂起,同时允许第二次操作与Qt中的第一次操作一起执行
- WTSFreeMemory在启动期间从服务调用时挂起-我应该省略吗
- C++HTTP客户端在GET请求后挂起read()调用