在没有 Send/Sync 特征的结构上采用 AtomicPtr
Adopt AtomicPtr on structs without Send/Sync traits
最近我正在尝试通过 psutil
crate 监控系统指标。 (我知道还有另一个库 heim
具有异步功能。)
我曾经使用 AtomicPtr
包装静态 Process
结构。编译器没有抱怨。但是很快我就遇到了 运行-time 错误,当我在 Process
对象上调用 API 时。
终于发现是AtomicPtr<Process>
的pid
变了,导致报错,因为新pid的进程不存在。
然后我尝试了另一种方法。我实施了以下 ProcessWrapper
,它有效。而 pid
并没有改变。
编辑:ProcessWrapper
是多余的,Process
本身与 Send/Sync
那么我的问题来了:
- 为什么第一种方法不行?
是因为Process
没有Send
特质?如果是这样,为什么编译器只是默认它?
我在 ProcessWrapper
上的第二次实施是否有任何潜在风险?如果存在,如何消除?
- 在下面的示例代码中,更有趣的是:当您取消对第二个实现的注释时,它们都起作用。但是为什么?
use psutil::process::Process;
use lazy_static::lazy_static;
use std::process;
use std::sync::{
atomic::{AtomicPtr, AtomicU64, Ordering}, Mutex, Arc
};
lazy_static!{
static ref PROCESS1 : AtomicPtr<Process> = AtomicPtr::new(&mut Process::new(process::id()).unwrap());
static ref PROCESS2: Arc<Mutex<Process>> = Arc::new(Mutex::new(
Process::new(std::process::id()).unwrap()
));
}
fn main() {
let process1 = unsafe{PROCESS1.load(Ordering::SeqCst).as_ref()}.unwrap();
//let process2 = &PROCESS2.lock().unwrap();
println!("{}", process1.pid()); // Unexpected! It is different from the real `process::id`
//println!("{}", process2.pid()); // It performs well, and it also makes the above one valid
println!("{}", process::id());
}
// redundant, the `Process` is with `Send/Sync` trait
use process_wrapper::*;
mod process_wrapper{
use psutil::process::{Process, ProcessResult,MemoryInfo};
use psutil::Percent;
#[derive(Debug)]
pub struct ProcessWrapper{
pub p: Process
}
unsafe impl Send for ProcessWrapper{}
unsafe impl Sync for ProcessWrapper{}
}
AtomicPtr::new(&mut Process::new(process::id()).unwrap())
您在堆栈上创建 Process
对象,并将指向该 堆栈 对象的可变指针存储到 AtomicPtr
中。 PROCESS1
完成初始化后,将释放 Process
对象,并且您的 AtomicPtr
指向未初始化的内存。
psutil:process::Process
既是 Send
又是 Sync
。 Arc<Mutex<Process>>
可以正常工作,而且很安全。不确定为什么需要 AtomicPtr
.
最近我正在尝试通过 psutil
crate 监控系统指标。 (我知道还有另一个库 heim
具有异步功能。)
我曾经使用 AtomicPtr
包装静态 Process
结构。编译器没有抱怨。但是很快我就遇到了 运行-time 错误,当我在 Process
对象上调用 API 时。
终于发现是AtomicPtr<Process>
的pid
变了,导致报错,因为新pid的进程不存在。
然后我尝试了另一种方法。我实施了以下 ProcessWrapper
,它有效。而 pid
并没有改变。
编辑:ProcessWrapper
是多余的,Process
本身与 Send/Sync
那么我的问题来了:
- 为什么第一种方法不行?
是因为Process
没有Send
特质?如果是这样,为什么编译器只是默认它? 我在ProcessWrapper
上的第二次实施是否有任何潜在风险?如果存在,如何消除?- 在下面的示例代码中,更有趣的是:当您取消对第二个实现的注释时,它们都起作用。但是为什么?
use psutil::process::Process;
use lazy_static::lazy_static;
use std::process;
use std::sync::{
atomic::{AtomicPtr, AtomicU64, Ordering}, Mutex, Arc
};
lazy_static!{
static ref PROCESS1 : AtomicPtr<Process> = AtomicPtr::new(&mut Process::new(process::id()).unwrap());
static ref PROCESS2: Arc<Mutex<Process>> = Arc::new(Mutex::new(
Process::new(std::process::id()).unwrap()
));
}
fn main() {
let process1 = unsafe{PROCESS1.load(Ordering::SeqCst).as_ref()}.unwrap();
//let process2 = &PROCESS2.lock().unwrap();
println!("{}", process1.pid()); // Unexpected! It is different from the real `process::id`
//println!("{}", process2.pid()); // It performs well, and it also makes the above one valid
println!("{}", process::id());
}
// redundant, the `Process` is with `Send/Sync` trait
use process_wrapper::*;
mod process_wrapper{
use psutil::process::{Process, ProcessResult,MemoryInfo};
use psutil::Percent;
#[derive(Debug)]
pub struct ProcessWrapper{
pub p: Process
}
unsafe impl Send for ProcessWrapper{}
unsafe impl Sync for ProcessWrapper{}
}
AtomicPtr::new(&mut Process::new(process::id()).unwrap())
您在堆栈上创建 Process
对象,并将指向该 堆栈 对象的可变指针存储到 AtomicPtr
中。 PROCESS1
完成初始化后,将释放 Process
对象,并且您的 AtomicPtr
指向未初始化的内存。
psutil:process::Process
既是 Send
又是 Sync
。 Arc<Mutex<Process>>
可以正常工作,而且很安全。不确定为什么需要 AtomicPtr
.