我正在嘗試在 rust lang中實作一些穩定性模式(在 cloud-native-go 中引入,例如https://github.com/cloud-native-go/examples/blob/main/ch04/circuitbreaker.go )。基本思想是將函式包裝在一個閉包中,該閉包保留有關函式呼叫的一些狀態。我也希望我的實作是執行緒安全的。
我終于想出了這樣的事情:
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
#[derive(PartialEq, Debug, Clone)]
pub(crate) enum Error {
UnReachable,
CircuitError,
}
pub(crate) type Circuit = Arc<Mutex<dyn Fn() -> Result<String, Error>>>;
pub(crate) fn fail_after(threshold: usize) -> Circuit {
let cnt = Arc::new(Mutex::new(0));
let f = move || {
let mut c = cnt.lock().unwrap();
*c = 1;
if *c > threshold {
return Err(Error::CircuitError);
} else {
return Ok("ok".to_owned());
}
};
return Arc::new(Mutex::new(f));
}
#[test]
fn test_debounce_first() {
let c = fail_after(1);
assert!(c.lock().unwrap()().is_ok());
assert!(c.lock().unwrap()().is_err());
}
#[test]
fn test_debounce_first_data_race() {
let c = fail_after(1);
let mut results = vec![];
for _ in 0..10 {
let d1 = Arc::clone(&c);
let h = thread::spawn(move || {
let r: Result<String, Error> = d1.lock().unwrap()();
r
});
results.push(h)
}
for result in results {
let r = result.join().unwrap();
assert!(r.is_ok())
}
}
(鐵銹游樂場)
多執行緒測驗給出編譯錯誤:
error[E0277]: `(dyn Fn() -> Result<String, Error> 'static)` cannot be sent between threads safely
--> src/lib.rs:41:17
|
41 | let h = thread::spawn(move || {
| ^^^^^^^^^^^^^ `(dyn Fn() -> Result<String, Error> 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn Fn() -> Result<String, Error> 'static)`
= note: required because of the requirements on the impl of `Sync` for `Mutex<(dyn Fn() -> Result<String, Error> 'static)>`
= note: required because of the requirements on the impl of `Send` for `Arc<Mutex<(dyn Fn() -> Result<String, Error> 'static)>>`
= note: required because it appears within the type `[closure@src/lib.rs:41:31: 44:10]`
note: required by a bound in `spawn`
我想知道我該如何解決這個問題?我已經用Arcand包裝了函式物件Mutex,為什么編譯器仍然抱怨?
uj5u.com熱心網友回復:
簡短回答:更改dyn Fn() -> Result<String, Error>為dyn Fn() -> Result<String, Error> Send 'static. 該型別的原始定義不保證dyn Fn生命周期有多長,也不保證它是否可以在執行緒之間安全地發送。
另一個注意事項,您可能需要進一步修改它,Box<dyn Fn() -> Result<String, Error> Send 'static>因為我看到您正在構建您的Mutex,new它需要它包含的型別是Sized,但是dyn Trait沒有大小。我從來沒有嘗試過構造一個大小不一的互斥鎖,所以你可能需要進一步研究。
編輯
你不需要裝箱,dyn Fn() -> _因為Arc<Mutex<_>>最初是用具體的閉包構造的,但是由于這里Mutex<dyn Fn() -> _>提到的第三個毯子實作和.ArcCoerceUnsized
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/475203.html
