5 ms·
glibc's impl is a "raw futex-based" one as well. I'm no great fan of glibc as an organization or body of code, but the comparative benefits of Rust here are not
by dundarious 4y ago
glibc's impl is a "raw futex-based" one as well. I'm no great fan of glibc as an organization or body of code, but the comparative benefits of Rust here are not well explained.
- tialaramex 4y agoAlthough glibc's implementation is indeed "raw futex-based" it is not merely a raw futex, of course. What you get from glibc isn't a futex (tricky to use properly) but instead a C structure type named pthread_mutex_t. It's quite big. 40 bytes! All Rust wanted was a futex, which for reference is just any 32-bit aligned value. The pthread_mutex_t is less useful to Rust, yet it's ten times bigger! So, Mara's new Mutex<T> in the Linux builds of Rust is just a futex (32-bits) plus a poison boolean plus your type T which is protected by the mutex. If your type is Zero Size then this rounds up to 8 bytes, five times smaller than pthread_mutex_t. If your type was just a u16 (unsigned 16-bit integer) then it rounds up to the same size, but you're also protecting your 16-bit unsigned integer which is nice. Now, if you're protecting huge data structures with mutexes, you don't care, it makes no measurable difference. But if you heard futex is small (it is) and protected loads of tiny objects with one each (say, individual 32-bit floating point X,Y co-ordinate pairs) Rust now makes your choice cost roughly what you expected instead of bloating your program for no reason. It's also a bit faster (but probably not enough that you should care) and simplifies some other book keeping in Rust itself. [ Above I wrote about Mutex, for Condvar the argument is similar but I haven't spent lots of time understanding the innards of Condvar whereas I spent a week reading Mutex stuff ]
- gpderetta 4y agoCondvar and mutexes are for very different use cases though, and condvars are notoriously hard to get right, especially when supporting all the full set of posix behaviours with good performance.
- tialaramex 4y agoYou need a mutex to actually use condition variables. So, even if Rust's Condvar were just as bulky and complicated as the POSIX one offered by glibc, you saved on the associated mutex. However from a quick glance Rust's Condvar is much smaller than pthread_cond_t Condition variables per se don't seem that difficult. Mara did the Linux and Windows condition variables, both are pretty elegant. As with a graceful swan, there is lots happening out of sight (in the futex code Rust needs to cope with the fact that when people do futexes for $notLinux including OpenBSD and Fuchsia they inevitably put a spin on the idea, adding something they thought was cool or ignoring a hard problem they didn't fancy solving) but the general idea is very simple. In contrast the glibc implementation is fiendishly complicated, but that's not because of POSIX, it's because they decided to do something fiendishly complicated, it hardly seems fair to demand that everybody who didn't need that complexity should respect how difficult it was anyway. Example, glibc promises if six threads A, B, C, D, E, F wait on a condition variable in order and then it is signalled exactly four times, threads A, B, C and D are definitely woken and E, and F are definitely not woken. That's potentially useful for some purposes, but it's expensive, what if I don't care about this? Too bad, the price is baked in even though POSIX says nothing about this feature. Rust doesn't care, so, if A, B, C, D, E, F wait on the CondVar and then it gets signalled exactly four times, well, four threads wake, but it could be any four. If A always waits again, signalling four times could just wake A four times, and each time it goes back to sleep. That seems useless, but if you wrote A, that's on you.
- gpderetta 4y agoFor what is worth, which threads are guaranteed to be unblocked is defined by the standard, at least under realtime scheduling. I'm sure the rust devs got their condvar implementation exactly right at the first try, including cancellation, RT support, support for robust mutexes, wait morphing, process shared cond vars, etc. For human programmers like the glibc ones, it took many decades, and there are very few that are confident enough to make large changes. As I understand, there was no posix correct cond var for windows for many years untill after vista MS decided to expose the right primitives.
- tialaramex 4y ago
- dundarious 4y agoThat's a much better justification for Rust's impl over glibc's. Given the comment this tree sprouted from, the argument seemed to be "Rust is memory safe and uses futex-es", which was pretty weak. I see the benefit of Rust here as being a kindof modern refresh of the building block concepts, which have calcified in standard C. With Rust, the refresh is now in std, or in a popular crate (where it is accessible via package managers). Alternative C standard libraries are hampered by having to implement awful parts (like locales, the string routines), and while C has an even greater quantity of excellent alternatives for smaller slices of "std" functionality (both open and closed source/in-house), discovery is less good. I'm not sold on every aspect of package managers, but I can't deny they have made some difficult things easy.