Check out http://www.greenteapress.com/ including:
Think Python : http://www.greenteapress.com/thinkpython/thinkpython.html
Think Bayes : http://www.greenteapress.com/thinkbayes/index.html
Think Complexity : http://www.greenteapress.com/complexity/index.html
Think Stats : http://www.greenteapress.com/thinkstats/index.html
Think OS: http://greenteapress.com/thinkos/
Semaphores are actually a horrible primitive for building concurrency. I sometimes call them "the goto of synchronization", which is deliberately ironic since they are a gift to the world from the "goto considered harmful" thinker, Dijkstra.
Debugging a problem with semaphores is difficult because they have no useful state beyond their count. You don't know how a set of semaphores might have gotten into a given state. (Vaguely analogous to the the argument that in a spaghetti program with backward gotos, it's difficult to have an idea of how control arrived at a particular node in the program.)
For instance, when we (ab)use a semaphore to simulate a mutex, that semaphore does not actually track the ownership: who is locking it now? It can be signaled by any task at all, whereas a proper mutex can diagnose the fact that it is unlocked by its owner.
Semaphores most certainly do not impose deliberate constraints that avoid programmers avoid errors, whatever that is supposed to mean, ouch!
When higher level primitives are correctly built on semaphores (condition variables, read-write locks, you name it), the solutions look like Rube Goldberg mousetraps. And that's before additional requirements are added like error checking, or handling priority inversion and whatnot.
Semaphores have one very good application and that is a situation in which a very fragile context (such as an interrupt service routine) needs to generate a wakeup signal. The semaphore signal operation can be made reentrant fairly easily. This is not only true in OS kernels. Note that in POSIX, for instance, the sem_post operation is noteworthy for being async-signal-safe, meaning that it can be called from a signal handler. By contrast, other things like pthread_cond_signal cannot be.
Ph.D. Computer Science, University of California at Berkeley, May 1997
M.S. Civil Engineering, Massachusetts Institute of Technology, August
B.S. Civil Engineering, Massachusetts Institute of Technology, June 19
It's extremely difficult to become a professor, so tenured or tenure-track professors at mediocre (but decent) schools often have degrees from big-name places.
Also, Olin College isn't even mediocre, just small. From what I understand it's pretty selective.