gpt4 book ai didi

multithreading - 不需要时强制使用 Mutex

转载 作者:行者123 更新时间:2023-11-29 07:56:27 25 4
gpt4 key购买 nike

我正在编写一个游戏并且有一个玩家列表定义如下:

pub struct PlayerList {
by_name: HashMap<String, Arc<Mutex<Player>>>,
by_uuid: HashMap<Uuid, Arc<Mutex<Player>>>,
}

这个结构体有添加、删除、获取玩家和获取玩家数量的方法。

NetworkServerServer共享此列表如下:

NetworkServer {
...
player_list: Arc<Mutex<PlayerList>>,
...
}

Server {
...
player_list: Arc<Mutex<PlayerList>>,
...
}

这是在 Arc<Mutex> 中因为NetworkServer在不同的线程(网络循环)中访问列表。
当玩家加入时,会为他们生成一个线程并将他们添加到 player_list 中。

虽然我正在做的唯一操作是添加到 player_list , 我被迫使用 Arc<Mutex<Player>>而不是更自然的 Rc<RefCell<Player>>HashMap这是因为 Mutex<PlayerList>需要它。我没有从网络线程(或任何其他线程)访问播放器,因此将它们放在 Mutex 下是没有意义的。 .只有 HashMap需要锁定,我正在使用 Mutex<PlayerList> 进行锁定.但是 Rust 很迂腐,想要防止所有的误用。

因为我只访问 Player在主线程中,每次都进行锁定既烦人又性能低下。有没有解决方法而不是使用 unsafe还是什么?

这是一个例子:

use std::cell::Cell;
use std::collections::HashMap;
use std::ffi::CString;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::thread;

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct Uuid([u8; 16]);

struct Player {
pub name: String,
pub uuid: Uuid,
}

struct PlayerList {
by_name: HashMap<String, Arc<Mutex<Player>>>,
by_uuid: HashMap<Uuid, Arc<Mutex<Player>>>,
}

impl PlayerList {
fn add_player(&mut self, p: Player) {
let name = p.name.clone();
let uuid = p.uuid;

let p = Arc::new(Mutex::new(p));
self.by_name.insert(name, Arc::clone(&p));
self.by_uuid.insert(uuid, p);
}
}

struct NetworkServer {
player_list: Arc<Mutex<PlayerList>>,
}

impl NetworkServer {
fn start(&mut self) {
let player_list = Arc::clone(&self.player_list);
thread::spawn(move || {
loop {
// fake network loop
// listen for incoming connections, accept player and add them to player_list.
player_list.lock().unwrap().add_player(Player {
name: "blahblah".into(),
uuid: Uuid([0; 16]),
});
}
});
}
}

struct Server {
player_list: Arc<Mutex<PlayerList>>,
network_server: NetworkServer,
}

impl Server {
fn start(&mut self) {
self.network_server.start();
// main game loop
loop {
// I am only accessing players in this loop in this thread. (main thread)
// so Mutex for individual player is not needed although rust requires it.
}
}
}

fn main() {
let player_list = Arc::new(Mutex::new(PlayerList {
by_name: HashMap::new(),
by_uuid: HashMap::new(),
}));
let network_server = NetworkServer {
player_list: Arc::clone(&player_list),
};
let mut server = Server {
player_list,
network_server,
};
server.start();
}

最佳答案

As I'm only accessing Players in the main thread, locking everytime to do that is both annoying and less performant.

你的意思是,现在你只能访问 Players在主线程中,但在以后的任何时候你可能会不小心在另一个线程中引入对它们的访问?

从语言的角度来看,如果你能得到一个值的引用,你就可以使用这个值。因此,如果多个线程引用了一个值,那么这个值应该可以安全地从多个线程使用。无法在编译时强制执行某个特定值,尽管可以访问,但实际上从未使用过。

然而,这提出了一个问题:

如果给定线程从未使用过该值,为什么该线程首先可以访问它?

在我看来,你有一个设计问题。如果您可以设法重新设计您的程序,以便只有主线程可以访问 PlayerList , 那么您将立即能够使用 Rc<RefCell<...>> .

例如,您可以改为让网络线程向主线程发送一条消息,宣布新玩家已连接。

目前,您正在“通过分享来交流”,您可以转向“通过交流来分享”。前者通常到处都有同步原语(例如互斥体、原子、...),并且可能面临争用/死锁问题,而后者通常有通信队列( channel )并且需要“异步”风格的编程。

关于multithreading - 不需要时强制使用 Mutex,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49782694/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com