std::函数作为sighandler_t
std::function as sighandler_t
如何指定lambda,std::bind result或任何其他std::function作为unix信号函数的参数?
我正在尝试以下操作
std::function<void(int)> handler1 = std::bind(&cancellation_token::cancel, &c);
std::function<void(int)> handler2 = [&c](int) { c.cancel(); };
但它不起作用,因为两者都
handler1.target<void(int)>()
和
handler2.target<void(int)>()
return null
如果我使用空闲函数指针初始化处理程序,它有效
void foo(int) { ... }
std::function<void(int)> handler = foo;
但这绝对没用。我需要捕获一些局部变量,所以我需要绑定或 lambda。
实际上我理解为什么它不起作用。文档说target
函数返回一个指向存储函数的指针,如果target_type() == typeid(T)
,否则为空指针。我不明白如何让它工作。
有什么建议吗?
由于它是由 bind
或 lambda 使用捕获的数据构造的,因此您无法将其转换为自由函数,因为target
函数通过 typeid
工作,std::function
将其保存在运行时中,而不是用于模板化function
的 T
类型。对于std::bind
,它将是一些库类型,对于 lambda,它将是一些未命名的类型。
您可以使用类似调度程序的方法,通过地图将信号编号与std::function
相关联。
你只需要一个映射来保存std::function
可以从自由函数访问:
std::unordered_map<int, std::function<void(int)>> signalHandlers;
还有一个通用处理程序(free函数)将信号号映射到函数:
void dispatcher(int signal) {
// this will call a previously saved function
signalHandlers.at(signal)(signal);
}
实现示例
主.cpp
#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;
}
CPP信号.cpp
#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);
}
}
CPP信号.hpp
#ifndef __CPPSIGNAL_HPP
#define __CPPSIGNAL_HPP
#include <functional>
namespace CppSignal {
void setHandler(int signal, const std::function<void(int)>& handler, int flags=0);
}
#endif
sighandler_t被定义为指向具有以下定义的函数的指针:
void func(int);
由于 std::bind 和 lambda 返回函子,因此不可能直接将它们用作信号处理程序。作为一种解决方法,您可以使用自己的包装器函数,例如
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);
}
};
使用SignalManager
的全局实例来管理单个信号
C++11 1.9 [intro.execution]/6:
当抽象机器的处理因接收信号而中断时,对象的值 都不是
类型为
volatile std::sig_atomic_t
也不是无锁原子对象 (29.4)
在执行信号处理程序期间未指定,并且任何 对象不在这两个中 处理程序修改的两个类别变为未定义。
在信号处理程序中实际可以移植的唯一操作是更改类型为 volatile std::sig_atomic_t
或无锁std::atomic
的标志的值(请注意,并非所有std::atomic
对象都是无锁的)。然后,非信号处理代码可以轮询该标志以响应信号的发生。
N3787 有一些关于如何修复 C++11 基本上中断信号处理程序的概念的有趣讨论。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗