Love vintage concurrency techniques :).
There's nothing vintage about them. Understanding these is crucial to understand how and why modern concurrency tools work. As I noted above in another comment, the issues that need mutexes or semaphores have never went away, only you might not realize that they're there. And please, don't come up with async/await, callback/continuation, node.js' async stuff. They are not a replacement for mutual exclusion, etc.
Linus Torvalds on semaphores (1999)
31–40 of 112 posts
Re: Linus Torvalds on semaphores (1999)
#32Earlier quoted context omitted.
From what I've heard, the P comes from "Probeer" (to "try"), and the V from "verhoog" (increase). This makes more sense to me.
That seems the correct one : https://cs.nyu.edu/~yap/classes/os/resources/origin_of_PV.ht...
Re: Linus Torvalds on semaphores (1999)
#33"Dijkstra was probably a bit heavy on drugs or something (I think the official explanation is that P and V are the first letters in some Dutch words, but I personally find the drug overdose story much more believable)." Quotes like this are why I always read what Linus has to say, regardless of whether the subject is relevant to my life in the slightest. Edit: Yes people, those Dutch words exist! I get it! I'm sure L…
If you use a word too common, it's too easy to confuse the definition of that word with the definition of its use in a different context. You must not understand the pain of reading two mathematical books and trying, with the utmost sincerity, to figure out whether the authors are actually using the words the same (such as set, relation, abstraction, object, even things like function). There's the distinct definition, and there is the contextual use, which can theoretically differ for everyone depending on the origin path of native language. You can never know if someone is altering the definition or discovering / describing something new, and they are using the wrong word. Discovering the perfect word for the concept you construct in code or math is an art.
Re: Linus Torvalds on semaphores (1999)
#34Here's Dijkstra's original paper on P and V (in Dutch), from about 1963. http://www.cs.utexas.edu/users/EWD/transcriptions/EWD00xx/EW... Here is a implementation of P and V, the original counted semaphore primitives, from 1972. http://www.fourmilab.ch/documents/univac/fang/ This is UNIVAC 1108 assembly code. Along with P and V is the code for bounded buffers, with the operations "PUT" and "GET". Bounded buffers are w…
> This stuff was all well understood four decades ago. Much of it was forgotten outside the mainframe world, because threads and multiprocessors didn't make it to microprocessors for several more decades. Here's an important distinction to make: this stuff was well understood in theory , but the practice is a bit different. Semaphores are a neat theoretical concept but not a very good practical parallel programming p…
And you don't necessarily need a mutex or to actually put the thread to sleep. Semaphores are also relevant when speaking of asynchronous stuff (e.g. Futures), in which case you can easily do CAS operations on an atomic reference holding an immutable queue of promises. Slightly inefficient under high contention, but non-blocking and gets the job done.
Re: Linus Torvalds on semaphores (1999)
#35it's surprising that Linus answers peacefully and pedagogically ! and thus it's a nice read to refresh the definition of semaphores, spinlocks and mutexes. Maybe you can edit the title and add a little [199] :-)
Linus spends much of his time being polite and helpful on many mailing lists, but it's his outbursts that make headlines, and convince the easily convincable that he's "rude".
Re: Linus Torvalds on semaphores (1999)
#36Re: Linus Torvalds on semaphores (1999)
#37Here's Dijkstra's original paper on P and V (in Dutch), from about 1963. http://www.cs.utexas.edu/users/EWD/transcriptions/EWD00xx/EW... Here is a implementation of P and V, the original counted semaphore primitives, from 1972. http://www.fourmilab.ch/documents/univac/fang/ This is UNIVAC 1108 assembly code. Along with P and V is the code for bounded buffers, with the operations "PUT" and "GET". Bounded buffers are w…
Well, P and V are considered harmful (pun intended). Systems using these operations are in general not "composable". In other words, it is usually not possible to compose two software systems using semaphores and/or mutexes, without rewriting these systems somehow. Alternatives exist. For example: message passing, and STM (software transactional memory). Anybody know of other alternatives?
Morealso STM doesn't solve the transactional problem that you face with using locks (mutex). Overall STM is just a fancy thing to have but hardly solves the big problem of transaction boundaries.
Message passing is easier to reason about due to global ordering but then you need some FIFO queues that are built upon some kind of mutex or spin lock... or Lamport based one (using for single producer-> single consumer one)... or some variant of Michael & Scott queue, etc.
In the end underneath you have to do the metal, so they cannot be 'considered harmful'.
Re: Linus Torvalds on semaphores (1999)
#38Random question, does anyone know what some more active newsgroups lists are today or has it all slowed down?
Re: Linus Torvalds on semaphores (1999)
#39Earlier quoted context omitted.
> This stuff was all well understood four decades ago. Much of it was forgotten outside the mainframe world, because threads and multiprocessors didn't make it to microprocessors for several more decades. Here's an important distinction to make: this stuff was well understood in theory , but the practice is a bit different. Semaphores are a neat theoretical concept but not a very good practical parallel programming p…
Semaphores are useful for rate limiting - for example say you have a connections pool with an upper bound, so naturally the number of threads that can acquire a connection and do things with it is limited by the size of that connections pool. And you don't necessarily need a mutex or to actually put the thread to sleep. Semaphores are also relevant when speaking of asynchronous stuff (e.g. Futures), in which case you…
Take the "rate limiting" example you mention (also one of Linus' examples in the OP). You initialize a semaphore to `max_concurrent_connections` and call `semaphore_down()` when you enter the connection handling sequence and `semaphore_up()` when you're done. Now this works fine and is an idiomatic example of using semaphores.
However, in the real world, this kind of situation rarely happens in isolation. What happens if you need to terminate the application for whatever reason, and do so cleanly? If you're under contention, you might have a dozen threads waiting for the semaphore go up and your only option is to kill them. Or implement some logic for this case (using another semaphore) to make sure the application hasn't been terminated while we were waiting for the rate limiting semaphore.
You can implement this cleanly using mutexes and conditions, by creating a "killable semaphore" synchronization primitive. While this is similar to a semaphore as an idea, it's very difficult to implement it if semaphores are the only primitive you have. Additionally, you probably want some kind of timeout if the queue is full.
So in practice you need something like:
while(true) {
socket = accept();
int status = rate_limiting_enter(my_rate_limiter);
// NOTE: someone else may call rate_limiting_terminate()
if(status == OK) {
service(socket);
rate_limiting_leave(my_rate_limiter);
} else if(status == TIMEOUT) {
send_busy(socket);
} else if(status == KILLED) {
send_terminate(socket);
break;
}
close(socket); // this must be called or resources leak
}
Now, while this is theoretically very similar to a semaphore, it has other real world priorities (like timeout and termination) which are very difficult to implement using Dijkstra -style semaphores with only P() and V() operations (and you definitely need more than one semaphore).This has been the case in almost every practical multithreaded programming scenario I've had. The solution could be thought of using semaphores (and I frequently do) but in practice, there's always some real world conditions (timing, contention, errors) that must be met.
It is very trivial to implement semaphore-like synchronization primitives using mutexes and conditions but not vice versa.
Semaphores are very good for textbook examples and a mental model but not so much in practical software.