Linux进程信号处理

xingyun86 2019-5-24 1880

头文件

/*
 * 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


×
打赏作者
最新回复 (0)
只看楼主
全部楼主
返回