There’s a lot of noise about how “Joe Biden’s government wants you to move away from using C++”. This is as a result of the US government releasing a report, Back to the building blocks: A path toward secure and measurable software which suggests:
Uncle Sam says "no!" “Memory safety vulnerabilities are a class of vulnerability affecting how memory can be accessed, written, allocated, or deallocated in unintended ways. Experts have identified a few programming languages that both lack traits associated with memory safety and also have high proliferation across critical systems, such as C and C++.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
In addition to managing the lifetimes of references to variables, the Rust compiler’s borrow checker also deals with enforcing Rust’s guarantees about mutability and so helps to prevent data races.
Basically, you can have any number of immutable references to a variable, but only if there are no mutable references to it at the same time, and you can only ever have a single mutable reference.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
One of the jobs of the Rust compiler’s “borrow checker” is to track the life of each reference to a variable so that it can prevent dangling references. To do this, it annotates each variable and reference with details of the scope in which it is valid. This annotation is called a lifetime.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
One reason that access shared data using locks is a bad idea is that, in complex code, it may be possible to deadlock. At their simplest, deadlocks are caused when one thread (thread a) obtains and holds a lock which another thread (thread b) requires whilst itself being blocked from obtaining a lock that it requires because thread b already holds it… Unfortunately, whilst Rust has eliminated data races in multithreaded code, it doesn’t prevent the possibility of deadlocks.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
Since I now understand a little about how to share data between threads I can try and use my Id Manager from multiple threads.
Following the same pattern as I’ve been using with the other threading code, something like this might work…
#[test] fn test_channel_thread_with_id_manager() { let id_manager = Arc::new(IdManager::<u8>::new(ReuseSlow)); let shared_manager = Arc::clone(&id_manager); let data = Arc::new(Mutex::new(HashMap::<String, Id<u8>>::new())); let shared_data = Arc::clone(&data); let mut thread = ChannelThread::new(move |message| { let id = shared_manager.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
Now that we can send messages to threads I want to see how we can access shared data from those threads. This isn’t the best design choice as shared data needs to be protected by locks so that it is accessed in an atomic fashion and the various threads involved with this data will contend with each other over the locks.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
The simplest threading is already covered by most Rust books. Starting up a thread, passing stuff to it, letting it run and waiting for it to finish.
Something like this is the basic thread example in Rust.
This work’s and is easy to understand and reason about. The spawned thread clearly runs for less time than the main thread as we join with it before the main thread completes but we rely on the spawned thread to decide when to shut down, this isn’t that important here as the spawned thread has a finite amount of work to do, but for threads that do a potentially infinite amount of work I will need a way to ask the thread to stop…
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
My threading background in C++ on Windows and Linux goes back a long way and that means that I have some set ways of doing things that may not map directly to the Rust way of doing things. I tend to use threads with the following patterns at present:
A thread starts up, waits on one or more externally controlled ’events’ and, when one of these is triggered the thread does something, or shuts down.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
Now that I have my generic IdManager I’d like to use it from multiple threads. As I said, this code would normally be used for things like connection ids for network protocols and I’ve spent the past 20 years or so writing servers that use small numbers of threads to handle many thousands of connections with work for each connection being given to a thread from a thread pool to perform.
Previously published This article was previously published on len-learns-rust.com. A full index of these articles can be found here.
I’ve now built a generic IdManager which does everything I want it to do, for now. I’ve bumbled along in a very non-scientific manner, mostly using the compiler errors to guide me towards things I’ve then looked up on the web. The code works and is tested, but it’s now time to go back to the books with a series of questions that this journey has got me thinking about: