Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 20, 2004 Waitable objects | ||||
---|---|---|---|---|
| ||||
I've fallen in love with D over the past few months and recently have begun to use for some serious work. I'm currently implementing a server with D and one of the things I'm missing is the ability to signal a mutex in order to wait on something else - i.e. Java's wait() and notify(). In Java, calling wait() on an object signals any synchronization lock so that other threads may operate on the synchronized object. Since I can't find a way to do the same via Phobos, I've ported a public domain waitiable mutex class from C++. This, of course, means that I have to use the mutex rather than the synchronized keyword and that eventually I will have to knock up Linux/Mac versions as well. While it's no big deal since the code is minimal, it would be a better fit (for portability and consistency) if the same functionality were built in to D. I'm sure others will eventually have need of it as well. So, does this already exist and I've overlooked it? And if not, would it be possible to include it in a future version? This isn't a show stopper. Just something I would love to see :) -- Mike Parker |
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to mike parker | Since my original post appears vague upon reading it, here's an example of what I mean:
void waitForSomething()
{
synchronized(someObject)
{
// the wait method signals/releases the synchronization lock on
// someObject so that other threads may operate on it.
while(someObject.isNotReady())
someObject.wait();
}
}
void doSomething()
{
synchronized(someObject)
{
someObject.doSomething();
// notify wakes up the waiting thread will then reacquire the lock
// on someObject
someObject.notify();
}
}
My current solution looks like this:
void waitForSomething()
{
someObject.mutex.lock();
if(someObject.isNotReady())
someObject.mutex.wait();
someObject.mutex.unlock();
}
void doSomething()
{
someObject.mutex.lock();
someObject.doSomething();
someObject.mutex.notify();
someObject.mutex.unlock();
}
The former is much more preferable methinks.
mike parker wrote:
> I've fallen in love with D over the past few months and recently have begun to use for some serious work. I'm currently implementing a server with D and one of the things I'm missing is the ability to signal a mutex in order to wait on something else - i.e. Java's wait() and notify().
>
|
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to mike parker | On Tue, 20 Apr 2004 19:59:43 +0000, mike parker <mike@aldacron.com> wrote: >I've fallen in love with D over the past few months and recently have begun to use for some serious work. I'm currently implementing a server with D and one of the things I'm missing is the ability to signal a mutex in order to wait on something else - i.e. Java's wait() and notify(). D's "synchronized" is implemented on Windows using CriticalSections (see src/phobos/internal/critical.c) and those can't be passed into the Windows wait functions. I don't know if/how Java-style synchronized/wait/notify can be implemented on top of CriticalSections or if it should go in std.thread. >In Java, calling wait() on an object signals any synchronization lock so that other threads may operate on the synchronized object. Since I can't find a way to do the same via Phobos, I've ported a public domain waitiable mutex class from C++. This, of course, means that I have to use the mutex rather than the synchronized keyword and that eventually I will have to knock up Linux/Mac versions as well. Can you give a URL to the C++ code? Does it contain other useful stuff besides mutex? A recent thread brought up Doug Lea's concurrent library for Java and some of us are looking at that right now. >While it's no big deal since the code is minimal, it would be a better fit (for portability and consistency) if the same functionality were built in to D. I'm sure others will eventually have need of it as well. So, does this already exist and I've overlooked it? And if not, would it be possible to include it in a future version? If the trade-off is performance of CriticalSections vs flexibility of Mutex I'd rather go with performance. Anyone know what the performance hit is to use Mutex? -Ben |
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to mike parker | > My current solution looks like this:
>
> void waitForSomething()
> {
> someObject.mutex.lock();
> if(someObject.isNotReady())
> someObject.mutex.wait();
> someObject.mutex.unlock();
> }
>
> void doSomething()
> {
> someObject.mutex.lock();
> someObject.doSomething();
> someObject.mutex.notify();
> someObject.mutex.unlock();
> }
Could using "auto" help? I haven't actually tried this and who knows what the performance would be, but I'm thinking of something like:
void waitForSomething()
{
auto AutoLock alock = someObject.mutex.autolock();
if(someObject.isNotReady())
alock.wait();
}
void doSomething()
{
auto AutoLock alock = someObject.mutex.autolock();
someObject.doSomething();
alock.notify();
}
|
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Ben Hinkle wrote: > D's "synchronized" is implemented on Windows using CriticalSections > (see src/phobos/internal/critical.c) and those can't be passed into > the Windows wait functions. I don't know if/how Java-style > synchronized/wait/notify can be implemented on top of CriticalSections > or if it should go in std.thread. I think it would be possible using Event objects. Based on an example from MSDN: user synchronizes on an object - D calls EnterCriticalSection user calls object.wait() - D calls LeaveCriticalSection - D calls WaitForSingleObject on an Event object associated with the lock user calls object.notify() - D signals the Event object via SetEvent - WaitForSingleObject returns, and immediately EnterCriticalSection is called to resume the lock Replace WaitForSingleObject with WaitForMultipleObjects, throw in an Event object array, and you have the basis for Object.notifyAll(). notify() would then just signal the first event in the queue. The Event objects would only need to be created/destroyed when wait() is called, or a number of them could be preallocated in a pool. The implementation I ported is a much more basic use of Event objects, boolean flags, and SignalObjectAndWait(). I'm a neophyte with Win32 threads yet (and MTing in general) so I'm not sure which way would be the most efficient. > Can you give a URL to the C++ code? Does it contain other useful stuff > besides mutex? A recent thread brought up Doug Lea's concurrent > library for Java and some of us are looking at that right now. http://www.jordanzimmerman.com/index.php?n=3&c=1 I didn't look through the site to see what else was there - just stumbled across the Mutex stuff via google. > If the trade-off is performance of CriticalSections vs flexibility of > Mutex I'd rather go with performance. Anyone know what the performance > hit is to use Mutex? I've looked at a few Win32 Mutex implementations in open source projects over the past couple of years and those which didn't use CriticalSections (which most did) used Event objects via CreateEvent rather than CreateMutex. I'm fairly certain this is because Event objects have less overhead than Mutex objects under the hood. Take a look at this MSDN article: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_locktest.asp It deals with something similar to what we're discussing, and the author provides implementations for each of the basic Win32 implementation objects. Pay particular attention to the performance chart near the bottom of the page. Mutex objects suck eggs there, with Semaphores not much better. Standard Events performed just as well as Crit sections. I would guess the same would be true here, but guesses mean nothing until benchmarked. |
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Ben Hinkle wrote:
>
> Could using "auto" help? I haven't actually tried this and who knows what
> the performance would be, but I'm thinking of something like:
>
> void waitForSomething()
> {
> auto AutoLock alock = someObject.mutex.autolock();
> if(someObject.isNotReady())
> alock.wait();
> }
>
> void doSomething()
> {
> auto AutoLock alock = someObject.mutex.autolock();
> someObject.doSomething();
> alock.notify();
> }
That would certainly make it look better :) But it's not the syntax that bothers me so much as the fact that the built-in synchronization has to be bypassed altogether.
|
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to mike parker | I agree that D could definately use some more OS-neutral features like mutexes, events, thread synchronization, etc. In the meantime, I may have something you can use that'll clean up your code: // Assumes that Mutex is a defined mutex class for brevity. // (The mutex itself could easily be encapsulated here though.) // note the use of the 'auto' keyword to make this sensitive to scoping rules. auto class Synchronized{ Mutex mutex; Synchronized(void* obj=this){ mutex.lock(obj); if(mutex.isNotReady()) mutex.wait(); } ~Sychronized(){ mutex.unlock(); } } // The gist here is that the Synchronized object automatically releases // its mutex when it falls out of scope. // Here's a threadsafe counter class using the Sychronized class: class Counter{ int count; void increment(){ Synchronized sync(this); count++; } int getCount(){ Synchronized sync(this); return(count); } } // To synchronize a single function, just declare as static int count; int incrementCount(){ static Synchronized sync(); count++; return(count); } I haven't coded in D for a while, but I have used a similar mechanism in C and C++ programs. Hope this helps. In article <c6315f$1vke$1@digitaldaemon.com>, mike parker says... > >Since my original post appears vague upon reading it, here's an example of what I mean: > > ... code example cut for brevity ... > >> I've fallen in love with D over the past few months and recently have begun to use for some serious work. I'm currently implementing a server with D and one of the things I'm missing is the ability to signal a mutex in order to wait on something else - i.e. Java's wait() and notify(). >> > |
April 20, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to eric anderton at yahoo dot com | Ick. Please ignore the single function example.. it won't work that way. Sorry for any confusion. In article <c63nep$5dt$1@digitaldaemon.com>, eric anderton at yahoo dot com says... > >I agree that D could definately use some more OS-neutral features like mutexes, events, thread synchronization, etc. In the meantime, I may have something you can use that'll clean up your code: > >// Assumes that Mutex is a defined mutex class for brevity. >// (The mutex itself could easily be encapsulated here though.) >// note the use of the 'auto' keyword to make this sensitive to scoping rules. > >auto class Synchronized{ >Mutex mutex; > >Synchronized(void* obj=this){ >mutex.lock(obj); >if(mutex.isNotReady()) mutex.wait(); >} > >~Sychronized(){ >mutex.unlock(); >} >} > >// The gist here is that the Synchronized object automatically releases >// its mutex when it falls out of scope. >// Here's a threadsafe counter class using the Sychronized class: > >class Counter{ >int count; > >void increment(){ >Synchronized sync(this); >count++; >} > >int getCount(){ >Synchronized sync(this); >return(count); >} >} > >// To synchronize a single function, just declare as static > >int count; > >int incrementCount(){ >static Synchronized sync(); >count++; >return(count); >} > >I haven't coded in D for a while, but I have used a similar mechanism in C and C++ programs. Hope this helps. > >In article <c6315f$1vke$1@digitaldaemon.com>, mike parker says... >> >>Since my original post appears vague upon reading it, here's an example of what I mean: >> >> ... code example cut for brevity ... >> >>> I've fallen in love with D over the past few months and recently have begun to use for some serious work. I'm currently implementing a server with D and one of the things I'm missing is the ability to signal a mutex in order to wait on something else - i.e. Java's wait() and notify(). >>> >> > > |
April 21, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle |
> D's "synchronized" is implemented on Windows using CriticalSections (see src/phobos/internal/critical.c)
oops - synchronized is in internal/monitor.c. I'm not sure now what critical.c is for. An object's monitor (on Windows) is a pointer to a CRITICAL_SECTION.
-Ben
|
April 21, 2004 Re: Waitable objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to mike parker | mike parker wrote: > Ben Hinkle wrote: > >> D's "synchronized" is implemented on Windows using CriticalSections (see src/phobos/internal/critical.c) and those can't be passed into the Windows wait functions. I don't know if/how Java-style synchronized/wait/notify can be implemented on top of CriticalSections or if it should go in std.thread. > > I think it would be possible using Event objects. Based on an example from MSDN: > > user synchronizes on an object > - D calls EnterCriticalSection > > user calls object.wait() > - D calls LeaveCriticalSection > - D calls WaitForSingleObject on an Event object associated with the > lock > > user calls object.notify() > - D signals the Event object via SetEvent > - WaitForSingleObject returns, and immediately > EnterCriticalSection is called to resume the lock Seems reasonable, though at first glance the multi-step actions in wait and notify would have to become atomic or wrapped in locks themselves, I think. Otherwise the notify could call SetEvent before the WaitForSingleEvent has happened. > Replace WaitForSingleObject with WaitForMultipleObjects, throw in an Event object array, and you have the basis for Object.notifyAll(). notify() would then just signal the first event in the queue. The Event objects would only need to be created/destroyed when wait() is called, or a number of them could be preallocated in a pool. The implementation I ported is a much more basic use of Event objects, boolean flags, and SignalObjectAndWait(). I'm a neophyte with Win32 threads yet (and MTing in general) so I'm not sure which way would be the most efficient. > >> Can you give a URL to the C++ code? Does it contain other useful stuff besides mutex? A recent thread brought up Doug Lea's concurrent library for Java and some of us are looking at that right now. > > http://www.jordanzimmerman.com/index.php?n=3&c=1 > > I didn't look through the site to see what else was there - just stumbled across the Mutex stuff via google. ok, thanks. I'll check it out. >> If the trade-off is performance of CriticalSections vs flexibility of Mutex I'd rather go with performance. Anyone know what the performance hit is to use Mutex? > > I've looked at a few Win32 Mutex implementations in open source projects over the past couple of years and those which didn't use CriticalSections (which most did) used Event objects via CreateEvent rather than CreateMutex. I'm fairly certain this is because Event objects have less overhead than Mutex objects under the hood. Take a look at this MSDN article: > > http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_locktest.asp > > It deals with something similar to what we're discussing, and the author provides implementations for each of the basic Win32 implementation objects. Pay particular attention to the performance chart near the bottom of the page. Mutex objects suck eggs there, with Semaphores not much better. Standard Events performed just as well as Crit sections. I would guess the same would be true here, but guesses mean nothing until benchmarked. ah. very interesting article. |
Copyright © 1999-2021 by the D Language Foundation