1

So if you had a MUD sever that handled each tcp connection in a separate process,

for stream in acceptor.incoming() {
    match stream {
        Err(e) => { /* connection failed */ }
        Ok(stream) => spawn(proc() {
            handle_client(stream)
        })
    }
}

What would be the strategy for sharing mutable world data for that server? I can imagine n connections responding to commands from the user. Each command needing to visit and possibly modify the world.

pub struct Server<'a> {
    world: World<'a>
}

pub struct World<'a> {
    pub chat_rooms: HashMap<&'a str, ChatRoom<'a>>
}


impl<'a> World<'a> {
    pub fn new() -> World<'a> {
        let mut rooms = HashMap::new();
        rooms.insert("General", ChatRoom::new("General"));
        rooms.insert("Help", ChatRoom::new("Help"));
        World{chat_rooms: rooms}
    }
}

Would Arc be the way to go?

let shared_server = Arc::new(server);
let server = shared_server.clone();

spawn(proc() {
    // Work with server
});

What about scaling to 100 or 1000 users? I'm just looking for a nudge in the right direction.

Bruce
  • 461
  • 1
  • 8
  • 17

1 Answers1

4

An Arc will let you access a value from multiple tasks, but it will not allow you to borrow the value mutably. The compiler cannot verify statically that only one task would borrow the value mutably at a time, and mutating a value concurrently on different tasks leads to data races.

Rust's standard library provides some types that allow mutating a shared object safely. Here are two of them:

  • Mutex: This is a simple mutual exclusion lock. A Mutex wraps the protected value, so the only way to access the value is by locking the mutex. Only one task at a time may access the wrapped value.
  • RWLock: This is a reader-writer lock. This kind of lock lets multiple tasks read a value at the same time, but writers must have exclusive access. This is basically the same rules that the borrow checker and RefCell have (except the lock waits until the borrow is released, instead of failing compilation or panicking).

You'll need to wrap a Mutex or a RWLock in an Arc to make it accessible to multiple tasks.

Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • With a `Mutex`, only one thread can be reading or writing at any time; with a `RWLock` can you have threads reading the value whilst one thread has it locked for writing? If they can, what do they read, the value as it was at the moment the write lock was obtained? – thecoshman Nov 10 '14 at 08:48
  • 1
    @thecoshman, no, with `RWLock` you can't have other threads reading while one thread is writing. Comparison with `&/&mut` is very correct here: `&mut` is an exclusive reference, while `&` is shareable. If you have `&mut`, you can't have another `&mut` or any `&`s. On the other hand, you can have arbitrary number of `&`s if there are no `&mut`. Exactly the same thing happens with `RWLock`. – Vladimir Matveev Nov 10 '14 at 09:06
  • @VladimirMatveev thanks for the clarification. It never hurts to restate some of this basic things that are easy to overlook. – thecoshman Nov 10 '14 at 11:09