[M3devel] condition variables/win32

jay.krell at cornell.edu jay.krell at cornell.edu
Wed Oct 21 02:58:28 CEST 2009


Something doesn't add up. I'll have to reread.  The paper I think  
assumes one mutex per condition, also clearly is talking about "our  
library". I'll need to compare the paper and the library. Could be the  
paper is wrong. A lot of literature here depends on atomic  
SignalAndWait but the docs just changed and no longer claim atomicity.

  - Jay (phone)

On Oct 20, 2009, at 2:05 PM, Tony Hosking <hosking at cs.purdue.edu> wrote:

> Should we not also consider fixing any problems in the existing  
> Win32 threading?  That paper does give a very straightforward recipe  
> for building Moulda-3 style mutex/condition semantics using  
> semaphores, which Windows does provide.
>
> On 20 Oct 2009, at 16:26, jay.krell at cornell.edu wrote:
>
>> I will read the paper, thanks.
>>
>> The java code demonstrates I believe some important applicable  
>> methods. I hope to have a "new" ThreadWin32.m3 "soon". In  
>> particular, no per-thread event, no wait lists, and counter to help  
>> matching up condition waits and signals. And no giant lock. And  
>> stil an efficient mutex with no kernel involvement unless there is  
>> contention, could/might use win32 criticalsection with little extra  
>> to avoid recursion, or could use something smaller. And no use of  
>> SignalObjectAndWait whose documentation recently changed to remove  
>> the atomicity claim!
>>
>>  - Jay (phone)
>>
>> On Oct 20, 2009, at 9:23 AM, "Randy Coleburn"  
>> <rcoleburn at scires.com> wrote:
>>
>>> Jay:
>>>
>>> I think we would need to delve deep into the implementation to be  
>>> able to answer all your questions precisely.
>>>
>>> I've attached a short paper by Andrew Birrell "Implementing  
>>> Condition Variables with Semaphores" that you may find  
>>> interesting / enlightening.
>>>
>>> My concern about using multiple mutex with same condition lies in  
>>> the queuing operations.  My recollection is that I've always  
>>> associated only one mutex with a condition variable, but that you  
>>> can have multiple conditions associated with the same mutex.
>>>
>>> I will go back and re-read Nelson again--its been a few years.
>>>
>>> Regards,
>>> Randy Coleburn
>>>
>>> >>> Jay K <jay.krell at cornell.edu> 10/18/2009 4:16 AM >>>
>>> I still have questions here.
>>>
>>> 1)
>>> Page 93 of the Nelson book:
>>> A monitor consists of some data, a mutex, and zero or more condition
>>> variables. A particular condition variable is always used
>>> in conjunction with the same mutex and its data.
>>>
>>> Doesn't this contradict the point made here?
>>> Does a condition variable always map to the same mutex
>>> or not?
>>>
>>> Or is this merely describing a typical usage pattern that is
>>> a subset of what interface Thread allows?
>>>
>>>
>>> 2)
>>> Can Wait only be satisfied by Signal/Broadcast,
>>> or also just via UnlockMutex?
>>>
>>>
>>> Depending on the answer to these questions,
>>> it seems you can largely merge mutex and condition variable.
>>>
>>>
>>> Condition variable is basically waiting for a
>>> thread to exit a mutex.
>>> Which is very very similar to LockMutex, except
>>> that it doesn't want to take the mutex in the uncontended
>>> case, it actually wants to wait for another thread
>>> to both acquire and release the mutex.
>>>
>>>
>>> I suspect I'm wrong on both of these.
>>> That condition variable really can use multiple mutexes.
>>> That exiting a mutex has no obligation to wake condition variables,
>>>   though it might be in good faith to do so...er..if it is
>>>   in good faith to not require programmer to use Signal/Broadcast.
>>>
>>>
>>> Thanks,
>>>  - Jay
>>>
>>>
>>>
>>> From: jay.krell at cornell.edu
>>> To: hosking at cs.purdue.edu; mika at async.async.caltech.edu
>>> Date: Thu, 8 Oct 2009 19:13:03 +0000
>>> CC: m3devel at elegosoft.com
>>> Subject: Re: [M3devel] condition variables/win32
>>>
>>> That seems a little strange to me but I guess I'll have to keep it  
>>> in mind.
>>>
>>>  - Jay
>>>
>>>
>>> From: hosking at cs.purdue.edu
>>> To: mika at async.async.caltech.edu
>>> Date: Thu, 8 Oct 2009 11:00:36 -0400
>>> CC: m3devel at elegosoft.com
>>> Subject: Re: [M3devel] condition variables/win32
>>>
>>> Sorry, yes, you are right of course!  The Modula-3 spec (and the  
>>> current pthreads-based implementation as also the win32  
>>> implementation I expect) do allow a condition variable being  
>>> mediated by different mutexes.  My comment was clouded by my  
>>> recollection from the pthreads spec that for pthread mutex/cv  
>>> behavior for other than 1 mutex per cv is undefined.  This  
>>> confusion may have been the source of prior bugs in the pthreads  
>>> threading implementation, but those bugs are gone now.  We support  
>>> the M3 spec properly.
>>>
>>> On 8 Oct 2009, at 10:34, Mika Nystrom wrote:
>>>
>>> Why can't you use the same condition variable with different  
>>> mutexes?
>>>
>>> This is dynamic, up to the M3 programmer, no?
>>>
>>> Tony Hosking writes:
>>>
>>> --Apple-Mail-96--321618545
>>> Content-Type: text/plain;
>>> charset=US-ASCII;
>>> format=flowed;
>>> delsp=yes
>>> Content-Transfer-Encoding: 7bit
>>>
>>> In general, it is OK in M3 to associate multiple conditions with the
>>> same mutex.  But not vice versa.
>>>
>>> On 8 Oct 2009, at 09:32, Jay K wrote:
>>>
>>> condition variables/win32
>>>
>>>
>>> So..one way I think about condition variables
>>> is that you want to be woken when someone else
>>> leaves the mutex that guards the data that you are dealing with.
>>> You want to know when another thread modifies the data.
>>> (If you have a reader/writer lock, you only want to be
>>> woken when someone exits a write.)
>>>
>>>
>>> Now, if you consider a producer/consumer queue.
>>> There are two interesting occurences.
>>> Transitions from empty to non-empty
>>> and transitions from full to non-full (optionally,
>>> if it is fixed size).
>>>
>>>
>>> Consumers wait for empty to non-empty.
>>> Consumers signal full to non-full.
>>> Producers wait for full to non-full.
>>> Producers signal non-empty to empty.
>>>
>>>
>>> So, in this case, one mutex is likely used with with two condition
>>> variables.
>>>
>>>
>>> But, what if we take a simplifying deoptimization and assume that a
>>> condition
>>> variable is only ever associated with one mutex?
>>> Anyone existing that mutex wakes up anyone waiting on any condition
>>> associated with it?
>>> Like, a condition variable I think becomes stateless and  
>>> everything is
>>> about the mutex?
>>>
>>>
>>> What is the downside?
>>>
>>>
>>> Condition variables are allowed to have spurious wakeups.
>>> This would "just" increase them. Too much?
>>>
>>>
>>> So, therefore, what would be wrong with the following design?
>>> a mutex contains an event
>>> and a number of waiters, zero or non-zero
>>> if a mutex is exiting with a non-zero number of waiters, signal the
>>> event
>>>
>>>
>>> To handle Signal vs. Broadcast
>>> method 1:
>>> the number of waiters might be interlocked
>>> the woken would decrement it
>>> if it isn't zero, signal the event again
>>>
>>>
>>> method 2:
>>> the number of waiters is both an integer and a semaphore
>>> and the lock exiter raises the semaphore by the the integer
>>>
>>>
>>> method 3:
>>> it is not an auto-reset event and there is a count
>>>  and when the count goes to 0, reset the event
>>> I think in this case you have to maintain a "wait generation"
>>> so that new waiters don't prevent the count from ever hitting 0.
>>> I think this #3 is what Java might be doing, and is described here:
>>> http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
>>> "3.3. The Generation Count Solution"
>>>
>>>
>>> also:
>>> http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
>>> 3.2. The SetEvent Solution
>>> Evaluating the SetEvent Solution
>>> Incorrectness --
>>>
>>>
>>> Is that incorrect case really necessarily incorrect?
>>> It seems unfair, since first waiter should be first woken, but..?
>>>
>>>
>>> Am I missing something? A lot?
>>>
>>>
>>> - Jay
>>>
>>>
>>> --Apple-Mail-96--321618545
>>> Content-Type: text/html;
>>> charset=US-ASCII
>>> Content-Transfer-Encoding: quoted-printable
>>>
>>> <html><body style=3D"word-wrap: break-word; -webkit-nbsp-mode:  
>>> space; =
>>> -webkit-line-break: after-white-space; "><div =
>>> apple-content-edited=3D"true"><span class=3D"Apple-style-span" =
>>> style=3D"border-collapse: separate; color: rgb(0, 0, 0); font- 
>>> family: =
>>> Helvetica; font-size: 12px; font-style: normal; font-variant:  
>>> normal; =
>>> font-weight: normal; letter-spacing: normal; line-height: normal; =
>>> orphans: 2; text-align: auto; text-indent: 0px; text-transform:  
>>> none; =
>>> white-space: normal; widows: 2; word-spacing: 0px; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size- 
>>> adjust: =
>>> auto; -webkit-text-stroke-width: 0; "><div style=3D"word-wrap: =
>>> break-word; -webkit-nbsp-mode: space; -webkit-line-break: =
>>> after-white-space; "><span class=3D"Apple-style-span" =
>>> style=3D"border-collapse: separate; -webkit-border-horizontal- 
>>> spacing: =
>>> 0px; -webkit-border-vertical-spacing: 0px; color: rgb(0, 0, 0); =
>>> font-family: Helvetica; font-size: 12px; font-style: normal; =
>>> font-variant: normal; font-weight: normal; letter-spacing: normal; =
>>> line-height: normal; -webkit-text-decorations-in-effect: none; =
>>> text-indent: 0px; -webkit-text-size-adjust: auto; text-transform:  
>>> none; =
>>> orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;  
>>> "><div =
>>> style=3D"word-wrap: break-word; -webkit-nbsp-mode: space; =
>>> -webkit-line-break: after-white-space; "><span class=3D"Apple- 
>>> style-span" =
>>> style=3D"border-collapse: separate; -webkit-border-horizontal- 
>>> spacing: =
>>> 0px; -webkit-border-vertical-spacing: 0px; color: rgb(0, 0, 0); =
>>> font-family: Helvetica; font-size: 12px; font-style: normal; =
>>> font-variant: normal; font-weight: normal; letter-spacing: normal; =
>>> line-height: normal; -webkit-text-decorations-in-effect: none; =
>>> text-indent: 0px; -webkit-text-size-adjust: auto; text-transform:  
>>> none; =
>>> orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;  
>>> "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate; =
>>> -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical- 
>>> spacing: =
>>> 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; =
>>> font-style: normal; font-variant: normal; font-weight: normal; =
>>> letter-spacing: normal; line-height: normal; =
>>> -webkit-text-decorations-in-effect: none; text-indent: 0px; =
>>> -webkit-text-size-adjust: auto; text-transform: none; orphans: 2; =
>>> white-space: normal; widows: 2; word-spacing: 0px; "><div><span =
>>> class=3D"Apple-style-span" style=3D"font-size: medium;"><font =
>>> class=3D"Apple-style-span" color=3D"#0000FF" face=3D"'Gill  
>>> Sans'">In =
>>> general, it is OK in M3 to associate multiple conditions with the  
>>> same =
>>> mutex.  But not vice versa.</font></span></div><div><font =
>>> class=3D"Apple-style-span" color=3D"#0000FF" face=3D"'Gill  
>>> Sans'"><span =
>>> class=3D"Apple-style-span" style=3D"font-size: =
>>> medium;"><br></span></font></div></span></span></span></span></ 
>>> span></span=
>>> </span></span></div></span></div></span></div><div><div>On 8 Oct  
>>> 2009, =
>>> at 09:32, Jay K wrote:</div><br =
>>> class=3D"Apple-interchange-newline"><blockquote  
>>> type=3D"cite"><span =
>>> class=3D"Apple-style-span" style=3D"border-collapse: separate;  
>>> color: =
>>> rgb(0, 0, 0); font-family: Helvetica; font-size: medium; font- 
>>> style: =
>>> normal; font-variant: normal; font-weight: normal; letter-spacing: =
>>> normal; line-height: normal; orphans: 2; text-align: auto; text- 
>>> indent: =
>>> 0px; text-transform: none; white-space: normal; widows: 2; word- 
>>> spacing: =
>>> 0px; -webkit-border-horizontal-spacing: 0px; =
>>> -webkit-border-vertical-spacing: 0px; =
>>> -webkit-text-decorations-in-effect: none; -webkit-text-size- 
>>> adjust: =
>>> auto; -webkit-text-stroke-width: 0px; "><div class=3D"hmmessage" =
>>> style=3D"font-size: 10pt; font-family: Verdana; ">condition =
>>> variables/win32<br> <br><br>So..one way I think about  
>>> condition =
>>> variables<br>is that you want to be woken when someone  
>>> else<br>leaves =
>>> the mutex that guards the data that you are dealing with.<br>You  
>>> want to =
>>> know when another thread modifies the data.<br>(If you have a =
>>> reader/writer lock, you only want to be<br>woken when someone  
>>> exits a =
>>> write.)<br> <br><br>Now, if you consider a producer/consumer =
>>> queue.<br>There are two interesting occurences.<br>Transitions  
>>> from =
>>> empty to non-empty<br>and transitions from full to non-full =
>>> (optionally,<br>if it is fixed size).<br> <br><br>Consumers  
>>> wait =
>>> for empty to non-empty.<br>Consumers signal full to =
>>> non-full.<br>Producers wait for full to non-full.<br>Producers  
>>> signal =
>>> non-empty to empty.<br> <br><br>So, in this case, one mutex  
>>> is =
>>> likely used with with two condition =
>>> variables.<br> <br><br>But, what if we take a simplifying =
>>> deoptimization and assume that a condition<br>variable is only  
>>> ever =
>>> associated with one mutex?<br>Anyone existing that mutex wakes up  
>>> anyone =
>>> waiting on any condition associated with it?<br>Like, a condition =
>>> variable I think becomes stateless and everything is<br>about the =
>>> mutex?<br> <br> <br>What is the =
>>> downside?<br> <br><br>Condition variables are allowed to have =
>>> spurious wakeups.<br>This would "just" increase them. Too =
>>> much?<br> <br><br>So, therefore, what would be wrong with the =
>>> following design?<br> a mutex contains an event<span =
>>> class=3D"Apple-converted-space"> </span><br> and a  
>>> number of =
>>> waiters, zero or non-zero<span =
>>> class=3D"Apple-converted-space"> </span><br> if a mutex  
>>> is =
>>> exiting with a non-zero number of waiters, signal the =
>>> event<br> <br><br>To handle Signal vs. Broadcast<br>method =
>>> 1:<br> the number of waiters might be  
>>> interlocked<br> the =
>>> woken would decrement it<br> if it isn't zero, signal the  
>>> event =
>>> again<br> <br><br>method 2:<br> the number of waiters is  
>>> both =
>>> an integer and a semaphore<br> and the lock exiter raises the =
>>> semaphore by the the integer<br><br> <br>method  
>>> 3:<br> it is =
>>> not an auto-reset event and there is a count<br>  and when  
>>> the =
>>> count goes to 0, reset the event<br> I think in this case you  
>>> have =
>>> to maintain a "wait generation"<span =
>>> class=3D"Apple-converted-space"> </span><br> so that new =
>>> waiters don't prevent the count from ever hitting 0.<br> I  
>>> think =
>>> this #3 is what Java might be doing, and is described here:<br><a =
>>> href=3D"http://www.cs.wustl.edu/~schmidt/win32-cv-1.html">http://www.cs.wu=
>>> stl.edu/~schmidt/win32-cv-1.html</a><br> "3.3. The Generation  
>>> Count =
>>> Solution"<br><br> <br>also:<br><a =
>>> href=3D"http://www.cs.wustl.edu/~schmidt/win32-cv-1.html">http://www.cs.wu=
>>> stl.edu/~schmidt/win32-cv-1.html</a><br>3.2. The SetEvent =
>>> Solution<br>Evaluating the SetEvent Solution<br>Incorrectness -- 
>>> <span =
>>> class=3D"Apple-converted-space"> </span><br> <br><br>Is  
>>> that =
>>> incorrect case really necessarily incorrect?<br>It seems unfair,  
>>> since =
>>> first waiter should be first woken, but..?<br><br> <br>Am I  
>>> missing =
>>> something? A lot?<br> <br><br> - =
>>> Jay<br></div></span></blockquote></div><br></body></html>=
>>>
>>> --Apple-Mail-96--321618545--
>>>
>>> <ImplementingCVs.pdf>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20091020/af529884/attachment-0001.html>


More information about the M3devel mailing list