Rust中使用libc::signal绑定impl方法作为SIGUSR1信号处理函数报错如何解决
问题原因
- 你尝试调用的
Foo::show是实例方法,隐含&self入参,函数签名和libc要求的信号处理函数签名完全不匹配:libc的信号处理要求C ABI的函数签名为extern "C" fn(libc::c_int) -> (),没有位置传递实例指针。 - 你之前写的
foo.show是方法调用表达式,不是函数指针本身,加括号后直接执行了方法得到()空返回值,自然无法转成usize。
解决方案
方案1:无状态结构体使用关联函数
如果你的Foo不需要存储任何状态,可以把show改成不带self的关联函数,且符合C调用约定即可:
use libc::{SIGUSR1, c_int}; use std::{thread, time}; struct Foo; impl Foo { // 匹配信号处理要求的C ABI关联函数 extern "C" fn show(_sig: c_int) { println!("Foo SIGNAL"); } } fn main() { unsafe { libc::signal(SIGUSR1, Foo::show as usize); } loop { println!("sleeping for 1 sec"); thread::sleep(time::Duration::from_secs(1)); } }
方案2:有状态结构体使用全局静态实例
如果你的Foo需要存储运行时状态,需要把实例放到全局静态变量中,保证信号处理时可以访问到:
use libc::{SIGUSR1, c_int}; use std::{thread, time}; use std::sync::Mutex; use once_cell::sync::Lazy; // Rust 1.63+也可以直接用标准库的静态Mutex实现 struct Foo { count: Mutex<i32>, // 存储信号触发次数的自定义状态 } impl Foo { fn new() -> Self { Foo { count: Mutex::new(0) } } fn show(&self) { let mut count = self.count.lock().unwrap(); *count += 1; println!("Foo SIGNAL, triggered {} times", count); } } // 全局静态Foo实例 static FOO_INSTANCE: Lazy<Foo> = Lazy::new(|| Foo::new()); // 信号处理中转函数 extern "C" fn signal_handler(_sig: c_int) { FOO_INSTANCE.show(); } fn main() { unsafe { libc::signal(SIGUSR1, signal_handler as usize); } loop { println!("sleeping for 1 sec"); thread::sleep(time::Duration::from_secs(1)); } }
注意:信号处理函数内只能执行异步信号安全的操作,上面例子中的println、Mutex锁严格来说不属于异步信号安全操作,生产环境使用时建议仅在信号处理函数内修改原子变量标记,在主业务循环中检测标记再执行对应逻辑,避免出现未定义行为。
内容的提问来源于stack exchange,提问作者yellowhat
相关产品推荐
相关产品推荐

