常用signal介绍
类型 | 值 | 动作 | 解释 |
---|---|---|---|
SIGHUP | 1 | A | 终端挂起或者控制进程终止 |
SIGINT | 2 | A | 终止信号(关联ctrl+c,只能结束前台进程) |
SIGABRT | 6 | C | 程序异常终止触发 |
SIGFPE | 8 | C | 错误的算术运算触发,对于那些处理复杂数学运算的程序,一般会建议你捕获该信号。 |
SIGKILL | 9 | AEF | 一旦该信号被交付给一个进程,那么这个进程就会终止。如果发生“非中断操作”会造成进程死锁,只有重启才会终止该进程。 |
SIGSEGV | 11 | C | 当程序没有权利访问一个受保护的内存地址时,或者访问无效的虚拟内存地址时(野指针),会产生这个信号 |
SIGPIPE | 13 | A | 管道破裂(无效的管道/不成立的管道) |
SIGTERM | 15 | A | 终止请求,并且在终止之前做一些清理活动。 |
*处理动作解释:
动作 | 意义 |
---|---|
A | 缺省的动作是终止进程 |
B | 缺省的动作是忽略此信号 |
C | 缺省的动作是终止进程并进行内核映像转储(dump core) |
D | 缺省的动作是停止进程 |
E | 信号不能被捕获 |
F | 信号不能被忽略 |
设置信号signal(registered signal, signal handler)
使用:
signal(SIGINT, sigfunc);
void sigfunc(int signo)
{
... //处理信号相关的操作
}
生成信号int raise (signal sig);
使用:
raise( SIGINT);
异常捕获示例:
1、代码中文件部分使用的QT
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <string>
#ifdef __linux
#include <execinfo.h> // 该文件只有Linux下 gcc 和 clang 中存在
#endif // __linux
const int MAX_STACK_FRAMES = 128;
void sig_crash(int sig)
{
time_t t = time(NULL);
tm* now = localtime(&t);
std::string strCurDay = QDate::currentDate().toString("yyyy_MM_dd");
QString qstrFileName = QString("%1/Error_Log_").arg(qstrFilePath) + strCurDay + QString(".txt");
FILE* fd = fopen(qstrFileName.toStdString().c_str(), "at");
if (NULL == fd)
{
exit(0);
}
try
{
char szLine[512] = {0, };
time_t t = time(NULL);
tm* now = localtime(&t);
sprintf(szLine,
"#########################################################\n"
"[%04d-%02d-%02d %02d:%02d:%02d][crash signal number:%d]\n",
now->tm_year + 1900,
now->tm_mon + 1,
now->tm_mday,
now->tm_hour,
now->tm_min,
now->tm_sec,
sig);
fwrite(szLine, 1, strlen(szLine), fd);
#ifdef __linux
void* array[MAX_STACK_FRAMES];
char** strings = NULL;
signal(sig, SIG_DFL);
int size = backtrace(array, MAX_STACK_FRAMES);
strings = (char**)backtrace_symbols(array, size);
for (int i = 0; i < size; ++i)
{
char szLine[512] = {0, };
sprintf(szLine, "%d %s\n", i, strings[i]);
fwrite(szLine, 1, strlen(szLine), fd);
std::string symbol(strings[i]);
size_t pos1 = symbol.find_first_of("[");
size_t pos2 = symbol.find_last_of("]");
std::string address = symbol.substr(pos1 + 1, pos2 - pos1 -1);
char cmd[128] = {0, };
sprintf(cmd, "addr2line -e test %s", address.c_str()); // test为应用程序名称,需要改为用户自己的应用程序名
FILE *fPipe = popen(cmd, "r");
if(fPipe != NULL){
char buff[1024];
memset(buff, 0, sizeof(buff));
char* ret = fgets(buff, sizeof(buff), fPipe);
pclose(fPipe);
fwrite(ret, 1, strlen(ret), fd);
}
}
free(strings);
#endif // __linux
}
catch (...)
{
//
}
fflush(fd);
fclose(fd);
fd = NULL;
exit(0);
}
int main()
{
// 捕捉崩溃日志
signal(SIGSEGV, sig_crash);
signal(SIGABRT, sig_crash);
// 测试部分(利用 stod 空字符串转double类型奔溃问题)
std::string strTest;
stod(strTest);
return 0;
}
2、抛去数据解析其他部分都用QT
#include <stdio.h>
#include <signal.h>
#include <QDateTime>
#ifdef __linux
#include <execinfo.h> // 该文件只有Linux下 gcc 和 clang 中存在
#endif // __linux
const int MAX_STACK_FRAMES = 128;
void sig_crash(int sig)
{
QString qstrFilePath = QString("%1/Log").arg(QCoreApplication::applicationDirPath());
QDir dir(qstrFilePath);
if(!dir.exists())
{
dir.mkpath(qstrFilePath);
}
QString strCurDay = QDate::currentDate().toString("yyyy_MM_dd");
QString qstrFileName = QString("%1/Error_Log_").arg(qstrFilePath) + strCurDay + QString(".txt");
QFile file(qstrFileName);
bool bIsOpen = file.open(QIODevice::Append | QIODevice::WriteOnly);
QTextStream text_stream(&file);
if(!bIsOpen)
{
exit(0);
}
try
{
QDateTime datetime = QDateTime::currentDateTime().toLocalTime();
text_stream << "#########################################################" << "\r\n";
text_stream << QString("[%1]").arg(datetime.toString("yyyy-MM-dd HH:mm:ss")) << "\r\n";
text_stream << QString("[crash signal number: %1]").arg(sig) << "\r\n";
#ifdef __linux
void* array[MAX_STACK_FRAMES];
char** strings = NULL;
signal(sig, SIG_DFL);
int size = backtrace(array, MAX_STACK_FRAMES);
strings = (char**)backtrace_symbols(array, size);
for (int i = 0; i < size; ++i)
{
text_stream << QString("[原始数据] %1").arg(strings[i]) << "\r\n";
std::string symbol(strings[i]);
size_t pos1 = symbol.find_first_of("[");
size_t pos2 = symbol.find_last_of("]");
std::string address = symbol.substr(pos1 + 1, pos2 - pos1 -1);
QString qstrCMD = QString("addr2line -e saimo %1").arg(QString::fromStdString(address));
FILE *fPipe = popen(qstrCMD.toStdString().c_str(), "r");
if(fPipe != NULL)
{
char buff[1024];
memset(buff, 0, sizeof(buff));
char* ret = fgets(buff, sizeof(buff), fPipe);
pclose(fPipe);
text_stream << QString("[分析错误] %1").arg(ret) << "\r\n";
}
}
free(strings);
#endif // __linux
}
catch (...)
{
//
}
file.flush();
file.close();
exit(0);
}
int main()
{
// 捕捉崩溃日志
signal(SIGSEGV, sig_crash);
signal(SIGABRT, sig_crash);
// 测试部分(利用 stod 空字符串转double类型奔溃问题)
std::string strTest;
stod(strTest);
return 0;
}