From: Caleb Clausen Date: 2010-05-06T08:08:40+09:00 Subject: [ruby-core:30039] Re: [Bug #3212] ConditionVariable may become inconsistent for interrupted threads On 5/5/10, Yusuke ENDOH wrote: > I think so, honestly. > We need contribution from those who are familiar with multi-thread > programing. I have some familiarity with threads from my real-time programming days. I'm willing to try to help out where and when I can. AFAICT, Silvain's proposed fix is mostly correct. I've made a couple of minor revisions below: the rescue clause should read 'rescue Exception' to ensure the cleanup happens on all exceptions, and I've added a raise at the end so the exception will be re-raised rather than having a normal return. Silvain, (or Yusuke, or anyone) please do correct me if either of these is wrong. def wait(mutex) t = Thread.current @waiters_mutex.synchronize do @waiters.push(t) end mutex.sleep rescue Exception @waiters_mutex.synchronize do @waiters.delete(t) end raise end It looks to me like real, actual semaphores would not have had this problem at all. I've so far been just skimming this particular issue, tho, because it's about condition variables which I understand but poorly and have philosophical objections to. Every time someone uses a condition variable, I think, "Why make it so complicated? Why not just use a semaphore?" (I can see that there is a use case for condvars in order to prevent a thread from holding a lock while it is waiting on some asynchronous event.... but most event waits do not fall neatly into this pattern. ) The problem with condvars is they're so hard to use. You need 3 separate data structures to use a condvar: the mutex that surrounds it, the condvar itself, and a flag variable to store the condvar's state. Those 3 have to be combined in the right way, or you end up with a hard to find bug. All that is fine if you actually need to wait while holding a lock. When you don't it's klunky and error-prone. With a semaphore, its all right in the semaphore, that's all you need. No mutex, no separate flag. You can just #give and #take the semaphore with a dirt-simple api. Of course, the problem with "just use a semaphore" in ruby is that there ARE NO semaphores in ruby. That's because ruby slavishly copies the pthreads API... which was written by a bunch of old unix hands who, like Yusuke, were not all that "familiar with multi-thread programing". So they slavishly copied what they read in the literature, which gave them only a partial view of the problem. (At least, that's my (distinctly unhumble) take on the situation.) I am convinced, however, that semaphores can be provided by MRI, both under the current regime of the giant interpreter lock and in the future when we have truly parallel threads. I can explain in detail if anyone wants to hear. Am I the only one who likes semaphores? Silvain, I'm particularly interested in hearing your opinion. Would a semaphore have suited your purposes as well as a condvar does?