头文件
/*
* CSignalHandler.h
*
*/
#ifndef _CSIGNALHANDLER_H_
#define _CSIGNALHANDLER_H_
#include <signal.h>
#include <time.h>
class CSignalHandler {
public:
static void init();
static bool wait(bool&flag);
private:
static sigset_t m_wait_mask;
static struct timespec m_time;
};
#endif /* _CSIGNALHANDLER_H_ */
源文件
/*
* CSignalHandler.cpp
*
* Linux下的线程实质上是轻量级进程(light weighted process),线程生成时会生成对应的进程控制结构,
* 只是该结构与父线程的进程控制结构共享了同一个进程内存空间。 同时新线程的进程控制结构将从父线程(进程)
* 处复制得到同样的进程信息,如打开文件列表和信号阻塞掩码等。由于我们是在子线程生成之后修改了信号阻塞掩
* 码,此刻子线程使用的是主线程原有的进程信息,因此子线程仍然会对SIGINT和SIGTERM信号进行反应,因此当
* 我们用Ctrl+C发出了 SIGINT信号的时候,主进程不处理该信号,而子进程(线程)会进行默认处理,即退出。
* 子进程退出的同时会向父进程(线程)发送SIGCHLD信号,表示子进程退出,由于该信号没有被阻塞,因此会导致
* 主进程(线程)也立刻退出,出现了前述的运行情况。因而该问题的一个解决方法是在子线程生成前进行信号设置,
* 或在子线程内部进行信号设置。
*/
#include <iostream>
#include "CSignalHandler.h"
sigset_t CSignalHandler::m_wait_mask;
struct timespec CSignalHandler::m_time;
//call this before thread create
void CSignalHandler::init(){
try{
signal(SIGKILL, SIG_IGN);
sigemptyset(&m_wait_mask);
sigaddset(&m_wait_mask, SIGINT);
sigaddset(&m_wait_mask, SIGQUIT);
sigaddset(&m_wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &m_wait_mask, 0);
} catch (std::exception& e){
std::cerr << "exception: " << e.what() << std::endl;
}
m_time.tv_sec=0;
m_time.tv_nsec =0;
}
bool CSignalHandler::wait(bool &flag){
try{
siginfo_t sig ;
switch(sigtimedwait(&m_wait_mask,&sig,&m_time)){
case SIGINT:
case SIGQUIT:
case SIGTERM:
flag=false;
break;
default:
break;
}
} catch (std::exception& e){
std::cerr << "exception: " << e.what() << std::endl;
}
return flag;
}
实践:
int main(int argc ,char **argv){
//step1 init
CSignalHandler::init();
//step2 create subthread
//step3 wait signal
while(CSignalHandler::wait(flag)){
sleep(1);
}
//step4 deal quit job
//save();
}
封装优化:
/**
* @file signalhandler.h
* @brief signalhandler defines
*/
#pragma once
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <time.h>
static bool m_flag;
static sigset_t m_wait_mask = {0};
static struct timespec m_time = { 0 };
class CSignalHandler {
public:
static void init() {
m_flag = true;
try {
//signal(SIGKILL, SIG_IGN);
sigemptyset(&m_wait_mask);
sigaddset(&m_wait_mask, SIGINT);
sigaddset(&m_wait_mask, SIGQUIT);
sigaddset(&m_wait_mask, SIGKILL);
sigaddset(&m_wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &m_wait_mask, 0);
}
catch (std::exception & e) {
std::cerr << "exception: " << e.what() << std::endl;
}
m_time.tv_sec = 0;
m_time.tv_nsec = 0;
}
static bool wait() {
//std::cout << "wait signal" << std::endl;
try {
siginfo_t siginfo = { 0 };
int sig = sigtimedwait(&m_wait_mask, &siginfo, &m_time);
switch (sig) {
case SIGINT:
case SIGQUIT:
case SIGKILL:
case SIGTERM:
{
m_flag = false;
std::cerr << "handled signal:" << sig << std::endl;
}
break;
default:
{
//std::cerr << "unhandled signal:" << sig << std::endl;
}
break;
}
}
catch (std::exception & e) {
std::cerr << "exception: " << e.what() << std::endl;
}
return m_flag;
}
};
#define G_SIGNAL_INIT CSignalHandler::init
#define G_SIGNAL_WAIT CSignalHandler::wait
__inline static int test_main()
{
printf("enter test_main()!\n");
// 初始化信号
G_SIGNAL_INIT();
while (G_SIGNAL_WAIT())
{
sleep(3);
}
printf("quit success!\n");
printf("leave test_main()!\n");
return 0;
}
在此优化:
/**
* @file signalhandle.h
* @brief signalhandle defines
*/
#pragma once
#include <iostream>
#include <string.h>
#include <signal.h>
#include <time.h>
class CSignalHandle {
private:
bool m_b_waiting;
sigset_t m_wait_mask;
struct timespec m_timespec;
public:
void init() {
memset(&m_wait_mask, 0, sizeof(m_wait_mask));
memset(&m_timespec, 0, sizeof(m_timespec));
try {
//signal(SIGKILL, SIG_IGN);
sigemptyset(&m_wait_mask);
sigaddset(&m_wait_mask, SIGINT);
sigaddset(&m_wait_mask, SIGQUIT);
sigaddset(&m_wait_mask, SIGKILL);
sigaddset(&m_wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &m_wait_mask, 0);
}
catch (std::exception & e) {
std::cerr << "exception: " << e.what() << std::endl;
}
m_b_waiting = true;
}
bool wait() {
std::cout << "wait signal" << std::endl;
try {
siginfo_t siginfo = { 0 };
int sig = sigtimedwait(&m_wait_mask, &siginfo, &m_timespec);
switch (sig) {
case SIGINT:
case SIGQUIT:
case SIGKILL:
case SIGTERM:
{
m_b_waiting = false;
std::cerr << "handled signal:" << sig << std::endl;
}
break;
default:
{
std::cerr << "unhandled signal:" << sig << std::endl;
}
break;
}
}
catch (std::exception & e) {
std::cerr << "exception: " << e.what() << std::endl;
}
return m_b_waiting;
}
public:
static CSignalHandle* GetInstance() {
static CSignalHandle inst;
return &inst;
}
};
#define G_SIGNAL_INIT CSignalHandle::GetInstance()->init
#define G_SIGNAL_WAIT CSignalHandle::GetInstance()->wait