C++ 标准::作为信号处理器的功能

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(); }; 但这绝对没有用。我需要捕获一些局部变

如何指定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(); };
但这绝对没有用。我需要捕获一些局部变量,所以我需要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:

当抽象机器的处理因接收到信号而中断时,对象的值 两者都不是

  • 类型
    volatile std::sig_atomic_t
    nor

  • 无锁原子对象(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