linux 多进程 信号,Linux 多线程处理信号

概 述

利用自己封装的线程类,来实现用线程处理信号

设置信号掩码

在之前的文章Linux 信号中,我们利用sigaction结构体中的sa_mask来设置进程的信号掩码。此外,可以使用sigprocmask()来设置或查看进程的信号掩码,函数原型如下:

#include

int sigprocmask(int _how, const sigset_t* _set, sigset_t* _oset);

而在多线程环境下,我们需要使用pthread版本的pthread_sigmask()来设置线程信号掩码,函数原型如下:

#include

#include

int pthread_sigmask(int how, const sigset_t* newmask, sigset_t* oldmask);

两个函数的参数意义一致,参数说明如下:

oldmask(_oset):若不为空,则输出原来的信号掩码

newmask(_set):指定新的信号掩码

how(_how):指定设置信号掩码的方式,可选值如下:

f6d04653ff36

可选值

信号线程

在上一篇文章Linux pthread封装中,我们实现了对pthread的封装,将线程函数定义为std::function。但在实际使用中,无法给线程传递参数。所以进行了修改,实现的线程基类如下(若有更好的实现方式,欢迎大佬指点):

//ThreadObject.h

#include

class ThreadObject {

public:

explicit ThreadObject();

virtual ~ThreadObject();

private:

pthread_t m_pthreadId;

bool m_isStarted;

bool m_isJoined;

static void* entryFunc(void *obj);

virtual void* run() = 0; //纯虚函数,在子类中实现

public:

void start();

void join();

void cancel();

bool started() const { return m_isStarted; }

};

//ThreadObject.cpp

#include

#include "ThreadObject.h"

ThreadObject::ThreadObject() :

m_pthreadId(0),

m_isStarted(false),

m_isJoined(false)

{

}

ThreadObject::~ThreadObject() {

if (m_isStarted && !m_isJoined) {

pthread_detach(m_pthreadId);

}

}

void ThreadObject::start() {

m_isStarted = true;

if (pthread_create(&m_pthreadId, nullptr, entryFunc, static_cast(this))) {

m_isStarted = false;

std::cout << "ThreadObject: Create a new thread failed!" << std::endl;

}

}

void ThreadObject::join() {

if (m_isStarted && !m_isJoined) {

m_isJoined = true;

pthread_join(m_pthreadId, nullptr);

}

}

void ThreadObject::cancel() {

if (!pthread_cancel(m_pthreadId)) {

m_isStarted = false;

}

}

void* ThreadObject::entryFunc(void *obj) {

ThreadObject* ptr = static_cast(obj);

ptr->run();

return nullptr;

}

创建线程处理线程类,继承于线程基类,重写run函数,示例代码如下:

//SignalThread.h

#include

#include "ThreadObject.h"

class SignalThread : public ThreadObject {

public:

explicit SignalThread();

~SignalThread() override;

void setSignalSet(sigset_t *set); //设置信号掩码集

private:

sigset_t *m_set; //信号掩码集

void *run() override;

};

//SignalThread.cpp

#include

#include "SignalThread.h"

SignalThread::SignalThread() = default;

SignalThread::~SignalThread() = default;

void SignalThread::setSignalSet(sigset_t *set) {

m_set = set;

}

void *SignalThread::run() {

int ret, sig;

for (;;) {

ret = sigwait(m_set, &sig);

if (ret == 0) {

std::cout << "SignalThread: Get signal: " << sig << std::endl;

}

}

}

实 现

最后,在服务器类中创建信号处理线程并运行,核心代码如下:

sigset_t set;

sigemptyset(&set);

sigaddset(&set, SIGQUIT); //添加信号集

sigaddset(&set, SIGUSR1);

ret = pthread_sigmask(SIG_BLOCK, &set, nullptr); //设置信号掩码

if (ret != 0) {

cout << "Server: pthread_sigmask error!" << endl;

return false;

}

// m_sigThread为信号处理线程对象

m_sigThread.setSignalSet(&set); //设置信号集

m_sigThread.start(); //开启信号处理线程

参考:《Linux高性能服务器编程》 游双 著

更多内容,详见GitHub:ChatRoomServer

更新 3.19

上文描述的无法给std::function传递参数的说法是有问题的,这里更正一下

对于std::function对象,可以通过bind来将类中的成员函数以及入参转化为function并执行,示例代码如下:

#include

#include //function bind

using namespace std;

function fun; //声明一个function类型,无入参,无返回值

class F {

public:

void func(int a, int b) { //类的成员函数

cout << a << " " << b << endl;

}

};

int main()

{

F f;

// 类的成员函数需要使用bind,并且需要实例化对象,成员函数要加&

fun = std::bind(&F::func, f, 1, 2); //传入参数

fun(); //直接调用函数

return 0;

}

注:函数的返回值需要保持一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值