Files
rust-users/examples/threading.rs
T
Benjamin Sago aa94ee89db Return Arcs instead of clones, and take &self
The primary goal of this commit was to avoid having to clone the users and groups it produces. The old implementation was written by me when I hadn't *fully* internalised how lifetimes worked, and just used `clone` to get around the error messages. It was only later that I realised how inefficient this actually is -- the values stored in the cache are never used, only their clones are!

Several attempt at this later, I settled on using `Arc` for everything and cloning *those* values instead.

All the gory details of what happened are written in a comment in the OS module. The short version is that it's now possible to change the `Users` trait's methods from taking `&mut self` to just taking `&self`. This is within the allowed uses of `Cell`: implementation details of a method that does actually return the same thing each time, which this is.

The main casualty is that the user now has to know about `Arc` and initialise a user with a username in such a container, which I hope to solve in a later commit.
2016-01-14 23:15:02 -10:00

61 lines
2.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! This example demonstrates how to use an `OSUsers` cache in a
//! multi-threaded situation. The cache uses `RefCell`s internally, so it
//! is distinctly not thread-safe. Instead, youll need to place it within
//! some kind of lock in order to have threads access it one-at-a-time.
//!
//! It queries all the users it can find in the range 500..510. This is the
//! default uid range on my Apple laptop -- Linux starts counting from 1000,
//! but I cant include both in the range! It spawns one thread per user to
//! query, with each thread accessing the same cache.
//!
//! Then, afterwards, it retrieves references to the users that had been
//! cached earlier.
// For extra fun, try uncommenting some of the lines of code below, making
// the code try to access the users cache *without* a Mutex, and see it
// spew compile errors at you.
extern crate users;
use users::{Users, OSUsers, uid_t};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::thread;
const LO: uid_t = 500;
const HI: uid_t = 510;
fn main() {
// For thread-safely, our users cache needs to be within a Mutex, so
// only one thread can access it once. This Mutex needs to be within an
// Arc, so multiple threads can access the Mutex.
let cache = Arc::new(Mutex::new(OSUsers::empty_cache()));
// let cache = OSUsers::empty_cache();
// Loop over the range and query all the users in the range. Although we
// could use the `&User` values returned, we just ignore them.
for uid in LO .. HI {
let cache = cache.clone();
thread::spawn(move || {
let cache = cache.lock().unwrap(); // Unlock the mutex
let _ = cache.get_user_by_uid(uid); // Query our users cache!
});
}
// Wait for all the threads to finish.
thread::sleep(Duration::from_millis(100));
// Loop over the same range and print out all the users we find.
// These users will be retrieved from the cache.
for uid in LO .. HI {
let cache = cache.lock().unwrap(); // Re-unlock the mutex
if let Some(u) = cache.get_user_by_uid(uid) { // Re-query our cache!
println!("User #{} is {}", u.uid, u.name)
}
else {
println!("User #{} does not exist", uid);
}
}
}