November 19, 2019

English | 日本語

Publishing Rust module in open source at crate.io (English)

I published the rust module (crate) spin-sync.

spin-sync behaves like std::sync except for spin-sync bases on spinlock (Wikipedia Spinlock.)

I hope you will download this package. Thank you!!

Why do I need a spinlock?

To reduce the size.

For example, each instance of std::sync::Mutex takes 40 bytes additionally in case of my computer (x86_64 Linux.) On the other hand, a spinlock usually requires only 1 extra byte. (So does spin-sync.)

Generally speaking, it is not a good idea to share one mutex among many objects; the more sharing objects, the more lock competitions. However, too many mutexes could request a lot of memory. The size of mutex itself is important in such cases.

Imagine implementing a database, for example.

Assume that it has an internal cache system and that the average size of each cached element is 160 bytes. If each cached element has one mutex, how much memory the mutex instances consume totally?

If each mutex takes 40 bytes, the summary goes to as much as 20 % of the memory for the cache. However, if it takes only 1 byte, the consumption is less than 1 %.

Why did I create a new crate package?

Similar crates have already been published as open source. It is true. spin is one of them.

It is famous and many programmers have been using it. However, it seems dangerous a little to me.

The interface of spin is different from that of std::sync

Unlikely std::sync, spin doesn’t implement a strategy called “poisoning”, which propagates panics among threads.

I don’t think it makes a big matter. Poisoning rarely helps to find a bug.

The problem is the interface difference.

For example, method std::sync::Mutex::lock(&self) returns a Result wrapping the lock guard; because it should be an error if the mutex has been poisoned. However, spin::Mutex::lock(&self) returns the lock guard itself.

In other words, it is not very easy to refactor code basing on std::sync into what using spin.

I hope if spin::Mutex::lock(&self) would return a Result. It is a tiny problem never to return a Result never to be an error.

Sometimes, it is not easy to test synchronous processing. I don’t like to refactor code basing on spin because I can’t refer to code using std::sync.

(spin-sync implements the “poisoning” feature and spin-sync::Mutex::lock(&self) returns Result.)

spin doesn’t implement trait !Sync for the guards

This is a serious problem because it can bring the rust safeguard to ruin.

For example, spin::MutexGuard implements Sync, while std::sync::MutexGuard implements !Sync.

Sync has the opposite meaning from !Sync, of course.

I don’t know the reason; possibly, because nightly 1 toolchain 2 is required. Rust sometimes deduces and implements Sync trait automatically. (This is why spin implements Sync.) The programmer has to implement the negative trait 3 to stop the deduction, and nightly toolchain is necessary to build such code except for the std library.

Thanks to !Sync, rust compiler can detect a potential bug. spin disables the feature. It could be difficult for programmers realize as such.

(spin-sync implements !Sync trait. Nightly build is necessary so far, unfortunately.)

1

Rust has 3 release channels; “stable”, “beta” and “nightly”. Nightly is the most unstable of the 3.

2

a set of tools to compile a rust program.

3

A negative trait is a trait starting with ‘!’.

How about the performance?

Generally speaking, the performance of a spinlock is better than that of a mutex. I think spin-sync is usually better than std::sync::Mutex.

Compared to spin, spin-sync could be slower because of the poisoning implementation. However, the difference is little, if any. I don’t think it makes a serious problem.