在Mutex的文档中,它说它实现了Send
和Sync
--这是有意义的,因为互斥体被设计为从多个线程访问,这些线程正在锁定、使用它保护的资源,然后解锁。
然而,在下面的代码中,我得到了一个编译器错误,据我所知,它抱怨互斥体没有实现Send/Sync:
error[E0599]: the method `try_init` exists for struct `SubscriberBuilder<DefaultFields, Format, tracing::level_filters::LevelFilter, std::sync::Mutex<MultiWriter>>`, but its trait bounds were not satisfied
--> src/main.rs:131:10
|
131 | .try_init().expect("setting default subscriber failed");
| ^^^^^^^^ method cannot be called on `SubscriberBuilder<DefaultFields, Format, tracing::level_filters::LevelFilter, std::sync::Mutex<MultiWriter>>` due to unsatisfied trait bounds
|
::: /Users/sean/.cargo/registry/src/github.com-1ecc6299db9ec823/tracing-subscriber-0.3.16/src/fmt/fmt_layer.rs:62:1
|
62 | / pub struct Layer<
63 | | S,
64 | | N = format::DefaultFields,
65 | | E = format::Format<format::Full>,
66 | | W = fn() -> io::Stdout,
67 | | > {
| | -
| | |
| |_doesn't satisfy `_: std::marker::Send`
| doesn't satisfy `_: std::marker::Sync`
|
= note: the following trait bounds were not satisfied:
`tracing_subscriber::fmt::Layer<Registry, DefaultFields, Format, std::sync::Mutex<MultiWriter>>: std::marker::Send`
`tracing_subscriber::fmt::Layer<Registry, DefaultFields, Format, std::sync::Mutex<MultiWriter>>: std::marker::Sync`
如果我从下面的代码中删除.with_writer(mw)
行,错误就会消失。很明显,问题与作者有关,但我不确定如何正确地做到这一点。
代码的目标是将tracing
框架中的日志写入stderr和dotenvy中指定的文件(如果指定了文件名,则为可选)。
注意:我使用的是最新的稳定版Rust和下面使用的每个机箱的发布版本,并在MacOS上用std,libc,alloc等(完整的Rust,而不是嵌入式)编译,但代码预计将在“多平台x86(_64)桌面”环境(Windows/MacOS/桌面Linux)下工作。
use std::fs::File;
use std::io::Write;
use std::sync::Mutex;
use dotenvy::var;
se std::sync::Arc;
use tracing::Level;
struct MultiWriter {
writers: Vec<Arc<dyn Write>>,
}
impl Write for MultiWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
for writer in self.writers.iter_mut() {
writer.write(buf)?;
}
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
for writer in self.writers.iter_mut() {
writer.flush()?;
}
Ok(())
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut writers: Vec<Arc<dyn Write>> = vec![(Arc::new(std::io::stderr()))];
if let Some(log_file) = var("log_file").ok() {
writers.push(Arc::new(File::create(log_file).unwrap()));
}
let mw = Mutex::new(MultiWriter { writers });
let tsb = tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env()).with_ansi(false)
.with_writer(mw);
if let Ok(log_level) = var("log_level") {
match log_level.to_uppercase().as_str() {
"TRACE" => tsb.with_max_level(Level::TRACE),
"DEBUG" => tsb.with_max_level(Level::DEBUG),
"INFO" => tsb.with_max_level(Level::INFO),
"WARN" => tsb.with_max_level(Level::WARN),
"ERROR" => tsb.with_max_level(Level::ERROR),
_ => tsb.with_max_level(Level::INFO)
}
.try_init().expect("setting default subscriber failed");
}
}
2条答案
按热度按时间xxb16uws1#
在Mutex的文档中,它说它实现了发送和同步
这并不完全正确:
这意味着只有当
T
为Send
时,互斥锁才为Send
和Sync
(原因在this question中描述。然而,T在这里不是
Send
:T
是struct MultiWriter
struct MultiWriter
包含一个dyn Write
不是Send
(至少不总是如此)struct MultiWriter
也不是。要解决此问题,请将
dyn Write
替换为dyn Write + Send
,它应该可以工作。km0tfn4u2#
我认为需要强调的是OP做的是
Mutex<Arc<MyType>>
,这和Arc<Mutex<MyType>>
是不同的,如果一个类型是Send
,并且 Package 在一个Mutex
中,那么整个事情就是Send + Sync
,但是由于Arc
两者都需要,这在这里很重要,但是如果Mutex
在外面(就像这里一样),那么Arc
并不满足于它里面的东西。正如Elias所引用的(正确的),
Mutex
只要求它所包含的值是Send
,而不是两个都是Send + Sync
。OP的问题(其中之一)是Mutex
在外面,Arc
要求两个Sync + Send
,而dyn Write
不是。弧:
互斥锁:
最终,@ChayimFriedman是正确的,对于OP的代码块,他们需要两者(
dyn + Write + Send + Sync
),但我想在这里写下更多关于 * 为什么 *。