Mutex and co

Share your advanced PureBasic knowledge/code with the community.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Mutex and co

Post 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
;
Last edited by blueznl on Tue Jun 05, 2007 7:19 pm, edited 4 times in total.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Very instructive, thanks for posting!
BERESHEIT
kinglestat
Enthusiast
Enthusiast
Posts: 746
Joined: Fri Jul 14, 2006 8:53 pm
Location: Malta
Contact:

Post by kinglestat »

thanks
I was curious about this...your post clarified the issue
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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)
:?:
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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:
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

It should be RelaseMutex_(). WaitForSingleObject_() is okay by the way.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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) ?
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

@Blue, ops! I believed every API object had a unique handle :o
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post 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.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post 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 :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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 :)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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)
Last edited by Blue on Sat Jul 05, 2008 7:34 pm, edited 1 time in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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.
Last edited by Blue on Sat Jul 05, 2008 7:41 pm, edited 1 time in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Post 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.)
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
Post Reply