在多个线程之间共享可变的自我 [英] Sharing mutable self between multiple threads

查看:56
本文介绍了在多个线程之间共享可变的自我的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一台服务器,可以接受来自多个客户端的连接。每个客户端可以向服务器发送一条消息,该消息将广播到所有其他客户端。问题在于处理每个连接的函数应具有对服务器的引用。但是,我想在单独的线程中处理连接,所以不能直接使用引用。

I have a server that accepts connections from multiple clients. Each client could send a message to the server, which is broadcast to all other clients. The problem is that the function that handles each connection should have a reference to the server. However, I want to handle the connections in separate threads, so I cannot use a reference directly.

由于作用域已弃用,我尝试将 self 包裹在 Arc 中,但随后出现了更多问题。以下是我的尝试:

Since scoped is deprecated, I tried wrapping self in an Arc, but more problems ensued. Below is my attempt:

struct Server {
    listener: TcpListener,
    clients: Vec<TcpStream>
}

impl Server {

    fn new() -> Server {
        Server { 
            listener : TcpListener::bind("127.0.0.1:8085").unwrap(),
            clients : vec![] 
        }
    }

    fn handle(&self) {
        println!("test");
    }

    fn start(mut self) {
        let mut handles = vec![];
        let a : Arc<Mutex<Server>> = Arc::new(Mutex::new(self));
        let mut selfm = a.lock().unwrap();

        // cannot borrow as mutable... ?
        for stream in selfm.listener.incoming() {
            match stream {
                Ok(stream) => {
                    selfm.clients.push(stream);
                    let aa = a.clone();
                    handles.push(thread::spawn(move || {
                        aa.lock().unwrap().handle();
                    }));
                },
                Err(e) => { println!("{}", e); },
            }
        }
    }

铁锈操场

我不知道该怎么办了,我担心所有这些锁都会出现死锁。您有任何建议吗?

I don't understand what to do anymore, and I fear deadlocks will arise with all these locks. Do you have any suggestions?

推荐答案

错误与多线程无关。正如编译器所说,问题是 selfm 已经在行

The error is pretty much unrelated to having multiple threads. The issue is, as the compiler says, that selfm is already borrowed in the line

for stream in selfm.listener.incoming() {

所以它不能可变地借用

selfm.clients.push(stream);

解决此问题的一种方法是分解 selfm 在循环之前,因此借用不会冲突。您的 start 方法将如下所示:

One way to fix this is to destructure selfm before the loop, so the borrows don't conflict. Your start method will then look as follows:

fn start(mut self) {
    let mut handles = vec![];
    let a : Arc<Mutex<Server>> = Arc::new(Mutex::new(self));
    let mut selfm = a.lock().unwrap();

     // destructure selfm here to get a reference to the listener and a mutable reference to the clients
    let Server { ref listener, ref mut clients} = *selfm;
    for stream in listener.incoming() { // listener can be used here
        match stream {
            Ok(stream) => {
                clients.push(stream); // clients can be mutated here
                let aa = a.clone();
                handles.push(thread::spawn(move || {
                    aa.lock().unwrap().handle();
                }));
            },
            Err(e) => { println!("{}", e); },
        }
    }
}

(话虽如此,您应该担心锁定是否正确,因为互斥锁将保持锁定状态,直到 selfm 超出范围,即仅当 start 终止,也就是永不终止。我会建议一种替代设计,但对我来说还不是很清楚,为什么要让线程访问服务器结构。

(That being said, you're right to be concerned about the locking, since the mutex will remain locked until selfm goes out of scope, i.e. only when start terminates, i.e. never. I would suggest an alternative design, but it's not really clear to me why you want the threads to have access to the server struct.)

这篇关于在多个线程之间共享可变的自我的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆