`libc::signal` 用于 `impl` 方法

`libc::signal` for `impl` method

我想在发送 SIGUSR1 信号时调用 impl 方法。

考虑以下示例:

use libc::SIGUSR1;
use std::{thread, time};

struct Foo {
}

impl Foo {
    fn show(&self) {
        println!("Foo SIGNAL")
    }
}

fn main() {
    let foo = Foo {};

    unsafe {
        libc::signal(SIGUSR1, foo.show as usize);
    }

    loop{
        println!("sleeping for 1 sec");
        thread::sleep(time::Duration::from_secs(1));
    }
}

我收到以下错误:

$ cargo run
   Compiling hello_world v0.1.0 (/home/vasco/a)
error[E0615]: attempted to take value of method `show` on type `Foo`
  --> src/main.rs:17:35
   |
17 |         libc::signal(SIGUSR1, foo.show as usize);
   |                                   ^^^^ method, not a field
   |
help: use parentheses to call the method
   |
17 |         libc::signal(SIGUSR1, foo.show() as usize);
   |                                       ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0615`.
error: could not compile `hello_world`

To learn more, run the command again with --verbose.

如果我听从建议 (libc::signal(SIGUSR1, foo.show() as usize);):

$ cargo run
   Compiling hello_world v0.1.0 (/home/vasco/a)
error[E0605]: non-primitive cast: `()` as `usize`
  --> src/main.rs:17:31
   |
17 |         libc::signal(SIGUSR1, foo.show() as usize);
   |                               ^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

error: aborting due to previous error

For more information about this error, try `rustc --explain E0605`.
error: could not compile `hello_world`

To learn more, run the command again with --verbose.

使用正常函数按预期工作:

use libc::SIGUSR1;
use std::{thread, time};

fn show() {
    println!("Foo SIGNAL")
}

fn main() {
    unsafe {
        libc::signal(SIGUSR1, show as usize);
    }

    let delay = time::Duration::from_secs(1);
    loop{
        println!("sleeping for 1 sec");
        thread::sleep(delay);
    }
}

有什么建议吗?

谢谢

感谢 Ahmed Masud:

use std::{thread, time};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

fn show() {
    println!("SHOW");
}

fn main() {

    loop {
        // Declare bool, setting it to false
        let term = Arc::new(AtomicBool::new(false));
        // Ask signal_hook to set the term variable to true when the program receives a SIGUSR1 kill signal
        signal_hook::flag::register(signal_hook::consts::SIGUSR1, Arc::clone(&term)).ok();
        show();

        while !term.load(Ordering::Relaxed) {
            println!("sleeping for 1 sec");
            thread::sleep(time::Duration::from_secs(1));
        }
    }
}

似乎按预期工作。

更新 1

上面的例子会每秒响应一次信号,不管什么时候触发信号,下面解决:

use std::io::Error;
use std::time::{SystemTime, UNIX_EPOCH};
use signal_hook::consts::signal::SIGUSR1;
use signal_hook::iterator::SignalsInfo;
use signal_hook::iterator::exfiltrator::WithOrigin;

fn show() {
    let a = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis();
    println!("show: {}", a);
}

fn mainloop() {
    let handle = std::thread::spawn(|| {
        loop {
            let a = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_millis();
            println!("main: {}", a);
            std::thread::sleep(std::time::Duration::from_secs(1));
        }
    });
    handle.join().unwrap();
}

fn main() -> Result<(), Error> {
    // Subscribe to the SIGUSR1 signal
    let sigs = vec![SIGUSR1];
    let mut signals = SignalsInfo::<WithOrigin>::new(&sigs)?;

    // Run the application in its own thread
    mainloop();

    // Consume all the incoming signals (this happens in "normal" Rust thread)
    for info in &mut signals {
        match info.signal {
            SIGUSR1 => {
                show();
            }
            _ => { // These are all the ones left
                eprintln!("Terminating");
                break;
            }
        }
    }

    Ok(())
}
$ cat Cargo.toml
[package]
...

[dependencies]
signal-hook = { version = "0.3", features = ["extended-siginfo"] }