George Russell wrote:
> What is the neatest solution?  There is an obvious solution, which is to
> crudely sequence all calls to lowerFlags by making them lock a single
> global variable (created using, sigh, unsafePerformIO) but this doesn't seem very
> elegant.  If MVar's were instances of Ord as well as Eq, a neat solution would
> be to always get the least MVar first, but they aren't.  So what should one do?

Okay, I thought about this a little more. You are very much on the right
track here. Breaking it down to fundamentals: somehow, some way, you
need to "lock" a Flag variable, so that if some other thread performs
lowerFlags with the same variable, it will wait. Then, considering that
the function takes two Flag variables in any arbitrary order, we can get
into a deadlock situation depending on which one is locked first. (We're
assuming that we can't lock them both simultaneously) Therefore, to get
around this, we need to impose some sort of ordering on the variables so
that one is always locked before the other, regardless of the order in
which they're passed.

Here's the solution: random. Since newFlag is declared IO Flag, you
should be able to easily embed a random number into the data type for
Flag. Granted, there is still the possibility that two Flag values get
assigned the same random number, in which case you won't know which one
will get locked first. But I think the odds of that happening are small
enough (unless you're generating billions of Flags and performing
trillions of lowerFlags calls).

A more sure-fire way of generating a unique number is to create a
"sequence" function, which will return the next number in a sequence
each time it's called. But again, such a function would require an
unsafePerformIO if it is to be used globally.

...or querying the system time, down to the nanosecond...

- Michael Hobbs

Reply via email to