www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - tango.core.sync.Mutex.tryLock

reply Jason House <jason.james.house gmail.com> writes:
tryLock does not seem to work as I expected.  I thought it returns if it 
was successful or not.  What could possibly cause the code below to 
fail?  I'm using linux.

myMutex.tryLock();
assert(myMutex.tryLock() == false); // fails
Jul 28 2007
parent reply Sean Kelly <sean f4.ca> writes:
Jason House wrote:
 tryLock does not seem to work as I expected.  I thought it returns if it 
 was successful or not.  What could possibly cause the code below to 
 fail?  I'm using linux.
 
 myMutex.tryLock();
 assert(myMutex.tryLock() == false); // fails

Locks in Tango are recursive, so you're guaranteed to succeed if you already hold the lock. Sean
Jul 28 2007
parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly wrote:
 Jason House wrote:
 tryLock does not seem to work as I expected.  I thought it returns if 
 it was successful or not.  What could possibly cause the code below to 
 fail?  I'm using linux.

 myMutex.tryLock();
 assert(myMutex.tryLock() == false); // fails

Locks in Tango are recursive, so you're guaranteed to succeed if you already hold the lock. Sean

Does that mean that the mutex locking and unlocking calls are thread aware? A given thread can repeatedly lock a mutex but must then unlock it the same number of times before the mutex is released for another thread to access it? I was trying to be creative with some queue structures. I wanted to add a blocking version of pop. If nothing is in the queue, wait for that to change... I was thinking that if I had a mutex that was automatically locked when the queue was empty, then I could implement blocking by quickly grabbing, then releasing a mutex. For an empty queue, the lock would sit and wait. It sounds like I can't use tango's Mutex class for this purpose because the push's and pop's are done by different threads. In fact, push calls are done by lots of threads. Is there anything in tango.core.sync that I should be using for this purpose?
Jul 28 2007
next sibling parent James Dennett <jdennett acm.org> writes:
Jason House wrote:
 Sean Kelly wrote:
 Jason House wrote:
 tryLock does not seem to work as I expected.  I thought it returns if
 it was successful or not.  What could possibly cause the code below
 to fail?  I'm using linux.

 myMutex.tryLock();
 assert(myMutex.tryLock() == false); // fails

Locks in Tango are recursive, so you're guaranteed to succeed if you already hold the lock. Sean

Does that mean that the mutex locking and unlocking calls are thread aware? A given thread can repeatedly lock a mutex but must then unlock it the same number of times before the mutex is released for another thread to access it? I was trying to be creative with some queue structures. I wanted to add a blocking version of pop. If nothing is in the queue, wait for that to change... I was thinking that if I had a mutex that was automatically locked when the queue was empty, then I could implement blocking by quickly grabbing, then releasing a mutex. For an empty queue, the lock would sit and wait. It sounds like I can't use tango's Mutex class for this purpose because the push's and pop's are done by different threads. In fact, push calls are done by lots of threads. Is there anything in tango.core.sync that I should be using for this purpose?

Aside from D, many system APIs for mutexes require that locking and unlocking be done by the same thread. Some will allow it to work across threads, and on some it will tend to work across threads until you turn on debugging options which will alert you to the potential problem. If D aims to be somewhat portable, it likely won't want to support designs which lock a mutex in one thread and then unlock it from another. -- James
Jul 28 2007
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
Jason House wrote:
 Sean Kelly wrote:
 Jason House wrote:
 tryLock does not seem to work as I expected.  I thought it returns if 
 it was successful or not.  What could possibly cause the code below 
 to fail?  I'm using linux.

 myMutex.tryLock();
 assert(myMutex.tryLock() == false); // fails

Locks in Tango are recursive, so you're guaranteed to succeed if you already hold the lock.

Does that mean that the mutex locking and unlocking calls are thread aware? A given thread can repeatedly lock a mutex but must then unlock it the same number of times before the mutex is released for another thread to access it?

Yes. And for what it's worth, this is largely an artifact of the OS implementations. Windows mutexes can only be recursive, though the feature must be enabled on some POSIX implementations. So Tango uses recursive mutexes largely for consistency, though I personally find them to be far more useful anyway (D 'synchronized' blocks are recursive as well).
 I was trying to be creative with some queue structures.  I wanted to add 
 a blocking version of pop.  If nothing is in the queue, wait for that to 
 change...  I was thinking that if I had a mutex that was automatically 
 locked when the queue was empty, then I could implement blocking by 
 quickly grabbing, then releasing a mutex.  For an empty queue, the lock 
 would sit and wait.
 
 It sounds like I can't use tango's Mutex class for this purpose because 
 the push's and pop's are done by different threads.  In fact, push calls 
 are done by lots of threads.  Is there anything in tango.core.sync that 
 I should be using for this purpose?

You should look at Condition. Use is something like this: auto myMutex = new Mutex; auto myCondition = new Condition( myMutex ); Thread A (producer): synchronized( myMutex ) { myQueue.push( data ); myCond.notify(); } Thread B (consumer): synchronized( myMutex ) { while( myQueue.isEmpty ) myCond.wait(); } In essence, Conditions are associated with a specific mutex, which is atomically unlocked when wait() is called. Thus, when thread B waits it allows thread A to enter the protected region to add more data to the queue. When wait unblocks it atomically acquires the mutex again, by which time thread A will have exited the protected region (earlier implementations actually blocked thread A and simply transferred control--this was indicated by 'signal' rather than 'notify'). Sean
Jul 29 2007
parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly wrote:
 You should look at Condition.  Use is something like this:
 
 auto myMutex = new Mutex;
 auto myCondition = new Condition( myMutex );
 
 Thread A (producer):
 
 synchronized( myMutex ) {
     myQueue.push( data );
     myCond.notify();
 }
 
 Thread B (consumer):
 
 synchronized( myMutex ) {
     while( myQueue.isEmpty )
         myCond.wait();
 }

Correct me if I'm wrong, but the Mutex operation of tango does not do strange interaction with the synchronized keyword? Wouldn't Thread B's "synchrnoized( myMutex )" cause Thread A to be unable to enter its "synchronized( myMutex )"?
 
 In essence, Conditions are associated with a specific mutex, which is 
 atomically unlocked when wait() is called.  Thus, when thread B waits it 
 allows thread A to enter the protected region to add more data to the 
 queue.  When wait unblocks it atomically acquires the mutex again, by 
 which time thread A will have exited the protected region (earlier 
 implementations actually blocked thread A and simply transferred 
 control--this was indicated by 'signal' rather than 'notify').
 
 
 Sean

Jul 29 2007
parent Sean Kelly <sean f4.ca> writes:
Jason House wrote:
 Sean Kelly wrote:
 You should look at Condition.  Use is something like this:

 auto myMutex = new Mutex;
 auto myCondition = new Condition( myMutex );

 Thread A (producer):

 synchronized( myMutex ) {
     myQueue.push( data );
     myCond.notify();
 }

 Thread B (consumer):

 synchronized( myMutex ) {
     while( myQueue.isEmpty )
         myCond.wait();
 }

Correct me if I'm wrong, but the Mutex operation of tango does not do strange interaction with the synchronized keyword? Wouldn't Thread B's "synchrnoized( myMutex )" cause Thread A to be unable to enter its "synchronized( myMutex )"?

Normally, yes. But myCond.wait() unlocks the mutex, allowing Thread A to enter. When wait returns, the lock is re-acquired.
 In essence, Conditions are associated with a specific mutex, which is 
 atomically unlocked when wait() is called.  Thus, when thread B waits 
 it allows thread A to enter the protected region to add more data to 
 the queue.  When wait unblocks it atomically acquires the mutex again, 
 by which time thread A will have exited the protected region (earlier 
 implementations actually blocked thread A and simply transferred 
 control--this was indicated by 'signal' rather than 'notify').


Sean
Jul 30 2007