我正在尝试处理一些* nix信号并具有以下代码:
// nix = "0.8.0"
extern crate nix;
use nix::sys::signal::{SaFlags, SigAction, sigaction, SIGINT, SigSet};
use nix::sys::signal::SigHandler::Handler;
extern fn interrupted(_:i32) {
println!("Interrupted");
}
fn main() {
let sigact = SigAction::new(Handler(interrupted), SaFlags::empty(), SigSet::thread_get_mask().unwrap());
if let Err(_) = unsafe { sigaction(SIGINT, &sigact) } {
println!("Failed to register handler");
std::process::exit(1);
}
loop {
println!("Hello");
}
}
我认为可以同时调用println!()
,但是当我中断
thread 'main' panicked at 'already borrowed: BorrowMutError', /checkout/src/libcore/result.rs:859
stack backtrace:
[...]
10: <std::io::stdio::StdoutLock<'a> as std::io::Write>::write
at /checkout/src/libcore/result.rs:761
at /checkout/src/libcore/cell.rs:670
at /checkout/src/libstd/io/stdio.rs:466
11: std::io::Write::write_all
at /checkout/src/libstd/io/mod.rs:957
12: <std::io::Write::write_fmt::Adaptor<'a, T> as core::fmt::Write>::write_str
at /checkout/src/libstd/io/mod.rs:1017
13: core::fmt::write
at /checkout/src/libcore/fmt/mod.rs:969
14: <std::io::stdio::Stdout as std::io::Write>::write_fmt
at /checkout/src/libstd/io/mod.rs:1028
at /checkout/src/libstd/io/stdio.rs:460
15: std::io::stdio::_print
at /checkout/src/libstd/io/stdio.rs:680
16: signals::interrupted
at ./Rust/signals/src/main.rs:8
[...]
println!()
的文档没有特别提及并发执行的任何恐慌,只是当它无法写入stdout时会感到恐慌。我对这种恐慌感到有些困惑,因为从循环中的多个线程调用println!()
可以正常工作。
问题是println!()
是否是线程安全的,但在同一个线程上不安全,即println!()
中main
的第一个实例时有一些线程本地静态依赖项被违反被中断,interrupted
中的第二个实例在同一个线程上被调用,或者我怎么能想象这个呢?
答案 0 :(得分:4)
问题是
println!()
是否是线程安全的,但在同一个线程上不安全,即println!()
中main
的第一个实例时有一些线程本地静态依赖项被违反被中断,interrupted
中的第二个实例在同一个线程[...]上调用?
是的,这是关于正确的。
println!()
代表print!()
代表std::io::_print
,调用RefCell
,通过传递print_to
作为参数来调用&LOCAL_STDOUT
。 LOCAL_STDOUT
的定义如下:
/// Stdout used by print! and println! macros
thread_local! {
static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = {
RefCell::new(None)
}
}
您看到的恐慌来自LOCAL_STDOUT
使用的Array.prototype.map()。信号处理程序在接收信号的线程上运行。因此,当发出信号时,信号处理程序可以在RefCell
可变地借用的同时运行。由于RefCell
一次只允许一次可变借用,因此尝试在信号处理程序中使用println!()
可能会引起恐慌。