C++ 标准::作为信号处理器的功能
如何指定lambda、std::bind result或任何其他std::函数作为unix信号函数的参数 我正在尝试下面的方法C++ 标准::作为信号处理器的功能,c++,c++11,lambda,function-pointers,C++,C++11,Lambda,Function Pointers,如何指定lambda、std::bind result或任何其他std::函数作为unix信号函数的参数 我正在尝试下面的方法 std::function<void(int)> handler1 = std::bind(&cancellation_token::cancel, &c); std::function<void(int)> handler2 = [&c](int) { c.cancel(); }; 但这绝对没有用。我需要捕获一些局部变
std::function<void(int)> handler1 = std::bind(&cancellation_token::cancel, &c);
std::function<void(int)> handler2 = [&c](int) { c.cancel(); };
但这绝对没有用。我需要捕获一些局部变量,所以我需要bind或lambda
事实上我理解为什么它不起作用。文档说明,如果target_type()==typeid(T)
,则target
函数返回指向存储函数的指针,否则返回空指针。我不知道如何使它工作
有什么建议吗?因为它是由
bind
或带有捕获数据的lambda构造的,所以不能将它转换为自由函数,因为target
函数是通过typeid
工作的,std::function
在运行时保存它,而不是为function
模板化的类型T
。对于std::bind
它将是一些库类型,对于lambda它将是一些未命名类型。signandler\t被定义为指向具有以下定义的函数的指针:
void func(int);
由于std::bind和lambdas返回functor,因此无法直接将它们用作信号处理程序。作为一种解决方法,您可以使用自己的包装函数,如
class SignalHandlerBase
{
public:
virtual void operator(int) = 0;
};
template <class T>
class SignalHandler : public SignalHandlerBase
{
T t;
public:
SignalHandler(T _t) : t(_t) { }
void operator(int i)
{
t(i);
}
};
class SignalManager
{
int sig;
SignalHandlerBase *shb;
static void handlerFunction(int i)
{
shb(i);
}
public:
SignalManager(int signal) : sig(signal), shb(nullptr) { signal(signal, &handlerFunction); }
template <class T>
void installHandler(T t)
{
delete shb;
shb = new SignalHandler<T>(t);
}
};
class SignalHandlerBase
{
公众:
虚空运算符(int)=0;
};
模板
类SignalHandler:PublicSignalHandlerBase
{
T;
公众:
SignalHandler(T_T):T(_T){
无效运算符(int i)
{
t(i);
}
};
班级信号经理
{
int-sig;
SignalHandlerBase*shb;
静态无效句柄函数(int i)
{
卫生福利局(一);
}
公众:
SignalManager(int信号):sig(信号),shb(nullptr){signal(信号,&handlerFunction);}
模板
无效installHandler(T)
{
删除shb;
shb=新的信号处理器(t);
}
};
使用SignalManager的全局实例来管理单个信号C++11 1.9[简介执行]/6: 当抽象机器的处理因接收到信号而中断时,对象的值 两者都不是
- 类型
norvolatile std::sig_atomic_t
- 无锁原子对象(29.4)
volatile std::sig_atomic\u t
或无锁的标记的值(请注意,并非所有std::atomic
对象都是无锁的)。然后,非信号处理代码可以轮询该标志以响应信号的出现
有一些关于如何修复C++11基本中断的信号处理程序的有趣讨论作为一个概念。您可以使用类似于调度程序的方法,通过映射将信号编号与
std::function
s相关联
您只需要一个映射来保存可从自由函数访问的std::function
s:
std::unordered_map<int, std::function<void(int)>> signalHandlers;
void dispatcher(int signal) {
// this will call a previously saved function
signalHandlers.at(signal)(signal);
}
实现示例 main.cpp
#包括
#包括
#包括
#包括“cppsignal.hpp”
int main(){
bool-stop=false;
//像这样简单地设置一个处理程序
CppSignal::setHandler(SIGINT,[&stop](int){stop=true;});
当(!停止){
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout OK。是否有其他方法可以在SIGINT处理程序中捕获局部变量?@axe仅使用gloval变量。OK。我将代码改为使用静态成员变量。谢谢。最好将对signal
的调用延迟到实际安装了信号处理程序,并在销毁符号时取消对信号的钩住alManager
。是的,你是对的。这只是一个简单的示例。安装新的OneHanks时,它可能还应该返回旧的处理程序。我使用的是std::atomic_bool,但这不是问题所在。
class SignalHandlerBase
{
public:
virtual void operator(int) = 0;
};
template <class T>
class SignalHandler : public SignalHandlerBase
{
T t;
public:
SignalHandler(T _t) : t(_t) { }
void operator(int i)
{
t(i);
}
};
class SignalManager
{
int sig;
SignalHandlerBase *shb;
static void handlerFunction(int i)
{
shb(i);
}
public:
SignalManager(int signal) : sig(signal), shb(nullptr) { signal(signal, &handlerFunction); }
template <class T>
void installHandler(T t)
{
delete shb;
shb = new SignalHandler<T>(t);
}
};
std::unordered_map<int, std::function<void(int)>> signalHandlers;
void dispatcher(int signal) {
// this will call a previously saved function
signalHandlers.at(signal)(signal);
}
#include <iostream>
#include <thread>
#include <csignal>
#include "cppsignal.hpp"
int main() {
bool stop = false;
// set a handler as easy as this
CppSignal::setHandler(SIGINT, [&stop] (int) { stop = true; });
while (!stop) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Bye" << std::endl;
return 0;
}
#include <cstring> // strsignal
#include <csignal>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include <mutex>
#include "signal.hpp"
namespace CppSignal {
std::timed_mutex signalHandlersMutex;
std::unordered_map<int, std::function<void(int)>> signalHandlers;
// generic handler (free function) to set as a handler for any signal
void dispatcher(int signal) {
std::unique_lock<std::timed_mutex> lock(signalHandlersMutex, std::defer_lock);
if (!lock.try_lock_for(std::chrono::seconds(1))) {
// unable to get the lock. should be a strange case
return;
}
auto it = signalHandlers.find(signal);
if (it != signalHandlers.end()) {
it->second(signal);
}
}
void registerHandler(int signal, const std::function<void(int)>& handler) {
std::lock_guard<std::timed_mutex> lock(signalHandlersMutex);
signalHandlers.emplace(signal, handler);
}
// this is the only method you will use
void setHandler(int signal, const std::function<void(int)>& handler, int flags) {
// configure sigaction structure
struct sigaction action;
if (sigfillset(&action.sa_mask) == -1) {
throw std::runtime_error("sigfillset failed");
}
action.sa_flags = flags;
action.sa_handler = dispatcher;
// set handler for the signal
if (sigaction(signal, &action, nullptr) == -1 && signal < __SIGRTMIN) {
throw std::runtime_error("Fail at configuring handler for signal: " + std::string(strsignal(signal)));
}
registerHandler(signal, handler);
}
}
#ifndef __CPPSIGNAL_HPP
#define __CPPSIGNAL_HPP
#include <functional>
namespace CppSignal {
void setHandler(int signal, const std::function<void(int)>& handler, int flags=0);
}
#endif