您如何可变地将单个结构实例共享给多个消费者(如服务)?
How do you mutablely share a single struct instance to multiple consumers (like a service)?
假设您有一个 HTTP API 作为计数器的接口。计数器状态存在于一个名为 CounterService
的对象中,您可以 increment()
计数器状态。
一个简单的 TypeScript 示例如下所示:
class CounterService {
public value: number = 0
public increment(): void {
this.value = this.value + 1
}
public decrement(): void {
this.value = this.value - 1
}
}
void function main() {
const api = express()
const counterService = new CounterService()
api.get('/value', getValueHandler(counterService))
api.post('/increment', incrementHandler(counterService))
api.post('/decrement', decrementHandler(counterService))
api.listen(3000)
}()
function getValueHandler(counterService: CounterService): express.Handler {
return function(req: express.Request, res: express.Response) {
res.send(counterService.value)
}
}
function incrementHandler(counterService: CounterService): express.Handler {
return function(req: express.Request, res: express.Response) {
counterService.increment()
res.sendStatus(204)
}
}
// ...
在上面的代码中,我将 counterService
对象共享给三个函数。一个需要只读访问权限,但其他两个都需要对其进行变异。
现在我明白这不是线程安全的,因为状态应该被锁定在互斥锁后面,所以我认为这是难题的一部分。不过,从广义上讲,有人如何在 rust 中实现与此类似的东西?
struct CounterService {
value: i32
}
impl CounterService {
fn increment(&mut self) {
self.value = self.value + 1
}
fn decrement(&mut self) {
self.value = self.value - 1
}
}
fn main {
//not sure how to make the equiv http server indicating callbacks, yet
}
好吧,你自己回答了 - 用 Mutex
包裹起来。它将为持有锁的人提供可变访问权限。
use std::sync::Mutex;
fn main() {
let svc = CounterService { value: 0 };
let data = Mutex::new(svc);
// .lock() does NOT require mut!
// Yet it gives you mutable access
let mut guard = data.lock().unwrap();
guard.increment();
drop(guard); // unlock the lock, so we can print the non-mut variable
println!("{:?}", data);
}
#[derive(Debug)]
struct CounterService {
value: i32,
}
impl CounterService {
fn increment(&mut self) {
self.value = self.value + 1
}
fn decrement(&mut self) {
self.value = self.value - 1
}
}
如果您想将它共享给多个处理程序,只需将 Mutex
包装在一个 Arc
中,这是一个线程安全的引用计数智能指针:
fn main() {
let svc = CounterService { value: 0 };
let shared = Arc::new(Mutex::new(svc));
handler_a(shared.clone());
handler_b(shared.clone());
handler_c(shared.clone());
}
假设您有一个 HTTP API 作为计数器的接口。计数器状态存在于一个名为 CounterService
的对象中,您可以 increment()
计数器状态。
一个简单的 TypeScript 示例如下所示:
class CounterService {
public value: number = 0
public increment(): void {
this.value = this.value + 1
}
public decrement(): void {
this.value = this.value - 1
}
}
void function main() {
const api = express()
const counterService = new CounterService()
api.get('/value', getValueHandler(counterService))
api.post('/increment', incrementHandler(counterService))
api.post('/decrement', decrementHandler(counterService))
api.listen(3000)
}()
function getValueHandler(counterService: CounterService): express.Handler {
return function(req: express.Request, res: express.Response) {
res.send(counterService.value)
}
}
function incrementHandler(counterService: CounterService): express.Handler {
return function(req: express.Request, res: express.Response) {
counterService.increment()
res.sendStatus(204)
}
}
// ...
在上面的代码中,我将 counterService
对象共享给三个函数。一个需要只读访问权限,但其他两个都需要对其进行变异。
现在我明白这不是线程安全的,因为状态应该被锁定在互斥锁后面,所以我认为这是难题的一部分。不过,从广义上讲,有人如何在 rust 中实现与此类似的东西?
struct CounterService {
value: i32
}
impl CounterService {
fn increment(&mut self) {
self.value = self.value + 1
}
fn decrement(&mut self) {
self.value = self.value - 1
}
}
fn main {
//not sure how to make the equiv http server indicating callbacks, yet
}
好吧,你自己回答了 - 用 Mutex
包裹起来。它将为持有锁的人提供可变访问权限。
use std::sync::Mutex;
fn main() {
let svc = CounterService { value: 0 };
let data = Mutex::new(svc);
// .lock() does NOT require mut!
// Yet it gives you mutable access
let mut guard = data.lock().unwrap();
guard.increment();
drop(guard); // unlock the lock, so we can print the non-mut variable
println!("{:?}", data);
}
#[derive(Debug)]
struct CounterService {
value: i32,
}
impl CounterService {
fn increment(&mut self) {
self.value = self.value + 1
}
fn decrement(&mut self) {
self.value = self.value - 1
}
}
如果您想将它共享给多个处理程序,只需将 Mutex
包装在一个 Arc
中,这是一个线程安全的引用计数智能指针:
fn main() {
let svc = CounterService { value: 0 };
let shared = Arc::new(Mutex::new(svc));
handler_a(shared.clone());
handler_b(shared.clone());
handler_c(shared.clone());
}