Building a stupid Mutex in the Rust

Firstly let’s understand what’s mutexes do

Let’s create a stupid mutex

use std::sync::atomic::{AtomicBool, Ordering};#[derive(Debug, Default)]
struct Mutex {
is_acquired: AtomicBool,
}
impl Mutex {
fn acquire(&self) {
while !self.is_acquired.swap(true, Ordering::AcqRel) {
// wait
}
}

fn release(&self) {
self.is_acquired.store(false, Ordering::Release);
}
}

Let’s signal the processor that it is inside a spin-loop

use std::sync::atomic::{AtomicBool, Ordering, spin_loop_hint};#[derive(Debug, Default)]
struct Mutex {
is_acquired: AtomicBool,
}
impl Mutex {
fn acquire(&self) {
while !self.is_acquired.swap(true, Ordering::AcqRel) {
spin_loop_hint() // Now we signals the processor that it is inside a busy-wait spin-loop
}
}

fn release(&self) {
self.is_acquired.store(false, Ordering::Release);
}
}

Making smart pointer from our stupid Mutex

use std::sync::atomic::{AtomicBool, Ordering, spin_loop_hint};
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
struct Mutex<T> {
is_acquired: AtomicBool,
data: UnsafeCell<T>,
}
impl<T> Mutex<T> {
fn new(data: T) -> Mutex<T> {
Mutex {
is_acquired: AtomicBool::default(),
data: UnsafeCell::new(data),
}
}
fn acquire(&self) -> MutexGuard<'_, T> {
while !self.is_acquired.swap(true, Ordering::AcqRel) {
spin_loop_hint() // Now we signals the processor that it is inside a busy-wait spin-loop
}
MutexGuard { mutex: &self }
}
fn release(&self) {
self.is_acquired.store(false, Ordering::Release);
}
}
struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.data.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.mutex.release()
}
}
// We need to force Send and Sync traits because our mutex has
// UnsafeCell, which don't realize it
// As long as T: Send, it's fine to send and share Mutex<T> between threads.
unsafe impl<T> Send for Mutex<T> where T: Send {}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
unsafe impl<T> Send for MutexGuard<'_, T> where T: Send {}
unsafe impl<T> Sync for MutexGuard<'_, T> where T: Send + Sync {}

Let’s write the test

use std::thread::spawn;
use std::sync::Arc;
#[test]
fn test() {
let num = 100;
let mutex = Arc::new(Mutex::new(0));
let ths: Vec<_> = (0..num)
.map(|_| {
let mutex = mutex.clone();
spawn(move || {
let mut lock = mutex.acquire();
*lock += 1;
})
})
.collect();
for thread in ths {
thread.join().unwrap();
}

let lock = mutex.acquire();

assert_eq!(*lock, num)
}

Conclusion

--

--

--

Software Developer from VK

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Preserving World’s information for Future Generations

My Journey to Certified Solutions Architect 2020 — SAA-C01

Integrating LVM with Hadoop and providing Elasticity to DataNode Storage

Mutable and Immutable objects in python.

Why choose RepoDb ORM over Dapper

Terraform Task 3 : Launch the Wordpress and MySQL

Database “Magic”​: Running Huge High Throughput-Low Latency KV Database with No Data In Memory

Experience Android App Development

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Mikhail Panfilov

Mikhail Panfilov

Software Developer from VK

More from Medium

Go: How I learned to stop worrying and switch Programming Languages

Concurrency in Go, Pony, Erlang/Elixir, and Rust

What boost can Apple’s M1 give to Redis?

What is a Bug?