Page 1 of 1

Mutex and co

Posted: Tue Jun 05, 2007 12:28 am
by blueznl
It's 3.94 as I was working on something older, but it still may provide some useful insight into mutexes. Now let's hope *I* got it right in the first place :-)

Code: Select all

; purebasic survival guide - pb3.94
; mutex_1.pb - 05.06.2007 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - creation and removal of mutexes
; - CreateMutex_()
; - CloseHandle_()
;
; note: purebasic 4's CreateMutex() command has not the same functionality as the Windows API CreateMutex_() !
;

#MUTEX_ALL_ACCESS = $1F0001
#WAIT_TIMEOUT     = $102
#WAIT_ABANDONED   = $80
#WAIT_FAILED      = $FFFFFFFF
#WAIT_OBJECT_0    = $0

;
; *** opening and closing a mutex
;
; mutexes are unique single objects that can be 'owned' by applications, they are exclusive and can never be owned
; by two different owners at the same time, thus 'mutually exclusive' or 'mutex'
;
; a return value of 0 means something when wrong with the creation of the mutex
;
mutex_name.s = "test"
;
mutex_h = CreateMutex_(0,0,@mutex_name)
If mutex_h = 0
  lasterror = GetLastError_()
  Debug "not created"
EndIf
;
; a mutex will be destroyed if nobody owns it, and 1. the creator exits, or 2. a closehandle closes it
; as usual the best way is to properly close a mutex if you no longer use it :-)
;
; one way to check for the existence of a mutex is opening it, in which case it returns a handle to the mutex
; if the mutex didn't exist (yet) or was destroyed via CloseHandle_() this will return 0
;
mutex2_h = OpenMutex_(#MUTEX_ALL_ACCESS,0,@mutex_name)
If mutex2_h = 0
  Debug "could not open"
Else
  CloseHandle_(mutex2_h)
EndIf
;
; trying to create a mutex that already existed will result in creating a copy of the specified mutex
; GetLastError_() provides information on the creation of the mutex, and if it already existed
;
; (this mechanism can be used to create 'single instance' software, where a new instance will exit as it already
; detects another version of itself in memory, by trying to create such a mutex and exiting when it already
; existed)
;
mutex3_h = CreateMutex_(0,0,@mutex_name)
lasterror = GetLastError_()
If lasterror = #ERROR_ALREADY_EXISTS
  Debug "already exists"
  CloseHandle_(mutex3_h)
EndIf
;
; although windows seems to clean up abandoned mutexes, it's better to clean them up properly
;
CloseHandle_(mutex_h)
;
;
;
; *** mutex ownership
;
; only one instance (program) can 'own' a mutex, ownership can be established upon creation
; (the second parameter when set to '#True' makes the creator an owner)
; other threads / instances would open the existing mutex using OpenMutex_()
;
;   mutex4_h = OpenMutex_(#MUTEX_ALL_ACCESS,0,@mutex_name)
;
mutex4_h = CreateMutex_(0,#True,@mutex_name)
;
; this program (the current instance, the code you're reading :-)) can try to get ownership of the mutex
; by calling WaitForSingleObject_() with a proper handle and a timeout parameter
;
; WaitForSingleObject_() will wait the specified nr. of milliseconds before continuing
;
result = WaitForSingleObject_(mutex4_h,50)
Select result
Case #WAIT_FAILED                                   
  Debug "failed"
Case #WAIT_ABANDONED
  Debug "other process abandoned mutex"
Case #WAIT_TIMEOUT
  Debug "other process still owns mutex"
Case #WAIT_OBJECT_0
  Debug "success"
EndSelect
;
; 'abandoned' is a special case, it means the mutex was found but the previous owner is gone now, and you
; have now become the owner of the mutex
;
; if you no longer need to own a mutex, releasing is easy
;
ReleaseMutex_(mutex4_h)
;
; using WaitForSingleObject_() and ReleaseObject_() makes it possible to synchronize two applications with each
; other
;
; finally, when we're all done and about to exit the program we close the mutex
;
CloseHandle_(mutex4_h)
;
; a final note (thanks netmaestro!): it's worth noting at this point that despite their similar names,
; the CreateMutex_() API and purebasic 4's native CreateMutex() command are very differen: the CreateMutex()
; command deals with the management of critical section objects rather than mutex objects
;

Posted: Tue Jun 05, 2007 1:40 am
by netmaestro
Very instructive, thanks for posting!

Posted: Fri Jun 08, 2007 8:45 am
by kinglestat
thanks
I was curious about this...your post clarified the issue

Posted: Thu Jul 03, 2008 3:18 pm
by Blue
I know I'm late in the game, but, just the same, many thanks for making me finally understand one of life's great mysteries !

From blueznl's explanations, I worked out a simple single instance test that works like a charm. It's here

Posted: Fri Jul 04, 2008 8:29 am
by Psychophanta
Thanks Blueznl, but:

Code: Select all

mutex_name.s = "test"
mutex_h = CreateMutex_(0,0,@mutex_name)
If mutex_h=0
  lasterror=GetLastError_()
  Debug "not created":End
EndIf
; one way to check for the existence of a mutex is opening it, in which case it returns a handle to the mutex  ?
mutex2_h=OpenMutex_(#MUTEX_ALL_ACCESS,0,@mutex_name)
If mutex2_h=0
  Debug "could not open"
Else
  If mutex_h=mutex2_h
    Debug "Yeah! That's true: it returns the handle to the mutex"
  Else
    Debug "Noah! That's not true: it does not return the handle to the mutex"
  EndIf
  CloseHandle_(mutex2_h)
EndIf
CloseHandle_(mutex_h)
:?:

Posted: Fri Jul 04, 2008 7:55 pm
by Blue
Psychophanta wrote:[[...]but:

Code: Select all

[...]
mutex_h = CreateMutex_(0,0,@mutex_name)
[...]
mutex2_h=OpenMutex_(#MUTEX_ALL_ACCESS,0,@mutex_name)
[...]
  If mutex_h=mutex2_h
    Debug "Yeah! That's true: it returns the handle to the mutex"
  Else
    Debug "Noah! That's not true: it does not return the handle to the mutex"
  EndIf
[...]
:?:
Psychophanta, does not your code simply demonstrate that CreateMutex_() and OpenMutex_() return 2 separate values ?
Both functions produce valid, yet different, handles to the mutex.
Your test simply validates what was explained by Blueznl, no?
...or am I being dense here? :shock:

Posted: Fri Jul 04, 2008 10:01 pm
by blueznl
It should be RelaseMutex_(). WaitForSingleObject_() is okay by the way.

Posted: Fri Jul 04, 2008 11:26 pm
by Blue
blueznl wrote:It should be RelaseMutex_(). WaitForSingleObject_() is okay by the way.
... instead of ???
Do you mean in lieu of CloseHandle_(mutex_h) ?

Posted: Sat Jul 05, 2008 8:58 am
by Psychophanta
@Blue, ops! I believed every API object had a unique handle :o

Posted: Sat Jul 05, 2008 9:07 am
by blueznl
Psycho, that's what I thought too, but appearently that is not the case. For example, many different objects can all be closed on the same way.

Posted: Sat Jul 05, 2008 9:09 am
by blueznl
Blue wrote:
blueznl wrote: It should be RelaseMutex_(). WaitForSingleObject_() is okay by the way.
... instead of ???
Do you mean in lieu of CloseHandle_(mutex_h) ?
I wasn't very clear, was I? :wink:

ReleaseObject_() is wrong, that should be ReleaseMutex_().

However, the use of WaitForSingleObject_() appears to be correct.

So. That's better :-)

Posted: Sat Jul 05, 2008 9:28 am
by Psychophanta
blueznl wrote:Psycho, that's what I thought too, but appearently that is not the case. For example, many different objects can all be closed on the same way.
Looks like Windows API is not well done, surely because it is done by much different programmers with different philosophies :)

Posted: Sat Jul 05, 2008 7:24 pm
by Blue
Psychophanta wrote:@Blue, ops! I believed every API object had a unique handle :o
Yeah, that's what I thought too, until I finally understood the meaning of "handle" (a numeric value, not necessarily unique, that allows access or reference to something)

Posted: Sat Jul 05, 2008 7:32 pm
by Blue
Psychophanta wrote:[...]Looks like Windows API is not well done, surely because it is done by much different programmers with different philosophies :)
I don't know if I'd use "not well done" to describe the API, but it certainly has become a mess over time. Just look at the dizzying number of different pre-defined constants available for handles and types. It's enough to make you lose your latin! And most of them are uselessly redundant.

It would be nice if it were possible to clean the slate and redo the whole thing anew, with only 3 objectives in mind:
simplification, simplification, simplification.

Posted: Sat Jul 05, 2008 7:37 pm
by Blue
blueznl wrote:ReleaseObject_() is wrong, that should be ReleaseMutex_().
OK, thanks.That's an important precision.
And now that you mention it, an obvious one at that ! :D
(Don't forget to make the correction in your excellent tutorial.)