- Dec
- 236
- 2
Here is my current implementation of a semaphore using a function and shared memory.
Line to use with FUNCTION:
semaphore=%@TRIM[%@execstr[0,SETLOCAL & SET Hndl=%@SMOPEN[8,Semaphore%1] & SET OHndl=%@SMPEEK[%Hndl,4,4] & IFF %OHndl == 0 THEN & SET RtnH=%@SMPOKE[%Hndl,4,4,%Hndl] & DELAY /M 2 & SET OHndl=%@SMPEEK[%Hndl,4,4] & IFF %OHndl != %Hndl THEN & SET RtnC=%@SMCLOSE[%Hndl] & SET Hndl=0 & ELSE & SET RtnP=%@SMPOKE[%Hndl,0,4,%_PID] & ENDIFF & ELSE & SET PID=%@SMPEEK[%Hndl,0,4] & IFF %PID == %_PID THEN & SET RtnC=%@SMCLOSE[%OHndl] & SET RtnH=%@SMPOKE[%Hndl,4,4,0] & SET RtnP=%@SMPOKE[%Hndl,0,4,0] & ENDIFF & SET RtnC=%@SMCLOSE[%Hndl] & SET Hndl=0 & ENDIFF & ECHO %Hndl & ENDLOCAL]]
Called using:
%@semaphore[name]
Lets look at what it does:
[01] SETLOCAL &
[02] SET Hndl=%@SMOPEN[8,Semaphore%1] &
[03] SET OHndl=%@SMPEEK[%Hndl,4,4] &
[04] IFF %OHndl == 0 THEN &
[05] SET RtnH=%@SMPOKE[%Hndl,4,4,%Hndl] &
[06] DELAY /M 2 &
[07] SET OHndl=%@SMPEEK[%Hndl,4,4] &
[08] IFF %OHndl != %Hndl THEN &
[09] SET RtnC=%@SMCLOSE[%Hndl] &
[10] SET Hndl=0 &
[11] ELSE &
[12] SET RtnP=%@SMPOKE[%Hndl,0,4,%_PID] &
[13] ENDIFF &
[14] ELSE &
[15] SET PID=%@SMPEEK[%Hndl,0,4] &
[16] IFF %PID == %_PID THEN &
[17] SET RtnC=%@SMCLOSE[%OHndl] &
[18] SET RtnH=%@SMPOKE[%Hndl,4,4,0] &
[19] SET RtnP=%@SMPOKE[%Hndl,0,4,0] &
[20] ENDIFF &
[21] SET RtnC=%@SMCLOSE[%Hndl] &
[22] SET Hndl=0 &
[23] ENDIFF &
[24] ECHO %Hndl &
[25] ENDLOCAL
Line 1/25: Protect variables
Line 2: Open the shared memory for the semaphore.
Line 3: Get the Shared Memory Handle that is currently holding the semaphore.
Line 4: If it is zero, there is is no handle holding the semaphore.
Line 5: Place the current Shared Memory Handle into the semaphore.
Line 6: Wait a period of time, this may vary depending on how fast your
computer is.
See comments below for more detail on why this is done.
Line 7: Read back the Shared Memory Handle back from Shared Memory.
Line 8: Has the handle changed?
See comments below for more detail on why this is done.
Line 9: If the handle has changed, we have lost the semaphore, close the
shared memory.
Line 10: Zero the Handle for return value in line 24.
Line 12: We retained the semaphore, store the process ID in the
semaphore.
Line 15: The handle in the semaphore is not empty, some process is
holding the semaphore. Get the process ID of the process
holding the semaphore.
Line 16: Is the process holding the semaphore the current process?
Line 17: Close the Share Memory Handle used originally to hold the
semaphore
Line 18: Zero out the semaphore's Shared Memory, this is necessary
because another process could have already opened access to
the semaphore in line 2.
Line 19: Zero out the semaphore's Shared Memory.
Line 21: Zero the Handle for return value in line 24.
Line 24: Return a value to the @execstr, this is either zero or the current
handle to the semaphore's shared memory.
Comment:
I originally required semaphores for critical sections within TCC's event handlers for
monitors. With FOLDMONITOR, I was get multiple event within a very short period of time.
In fact the semaphore itself was prone to problems where multiple processes could get
to line 5 at the same time. This could mean that more than one process could hold the
semaphore. Line 6 to 8 prevents this, basically the last of these processes to get to
line 5 gets to hold the semaphore.
Usage:
I usually use the semaphores as follows:
DO WHILE %@Semaphore[Event1] == 0 (DELAY /M 1)
DO WHILE %@Semaphore[Event2] == 0 (DELAY /M 1)
IFF %@Semaphore[Event1] == 0 THEN
REM
REM Start Critical Section
REM
IFF %@Semaphore[Event2] != 0 THEN
Echo Error on Semaphore Event2
ENDIFF
ELSE
Echo Error on Semaphore Event1
ENDIFF
Line to use with FUNCTION:
semaphore=%@TRIM[%@execstr[0,SETLOCAL & SET Hndl=%@SMOPEN[8,Semaphore%1] & SET OHndl=%@SMPEEK[%Hndl,4,4] & IFF %OHndl == 0 THEN & SET RtnH=%@SMPOKE[%Hndl,4,4,%Hndl] & DELAY /M 2 & SET OHndl=%@SMPEEK[%Hndl,4,4] & IFF %OHndl != %Hndl THEN & SET RtnC=%@SMCLOSE[%Hndl] & SET Hndl=0 & ELSE & SET RtnP=%@SMPOKE[%Hndl,0,4,%_PID] & ENDIFF & ELSE & SET PID=%@SMPEEK[%Hndl,0,4] & IFF %PID == %_PID THEN & SET RtnC=%@SMCLOSE[%OHndl] & SET RtnH=%@SMPOKE[%Hndl,4,4,0] & SET RtnP=%@SMPOKE[%Hndl,0,4,0] & ENDIFF & SET RtnC=%@SMCLOSE[%Hndl] & SET Hndl=0 & ENDIFF & ECHO %Hndl & ENDLOCAL]]
Called using:
%@semaphore[name]
Lets look at what it does:
[01] SETLOCAL &
[02] SET Hndl=%@SMOPEN[8,Semaphore%1] &
[03] SET OHndl=%@SMPEEK[%Hndl,4,4] &
[04] IFF %OHndl == 0 THEN &
[05] SET RtnH=%@SMPOKE[%Hndl,4,4,%Hndl] &
[06] DELAY /M 2 &
[07] SET OHndl=%@SMPEEK[%Hndl,4,4] &
[08] IFF %OHndl != %Hndl THEN &
[09] SET RtnC=%@SMCLOSE[%Hndl] &
[10] SET Hndl=0 &
[11] ELSE &
[12] SET RtnP=%@SMPOKE[%Hndl,0,4,%_PID] &
[13] ENDIFF &
[14] ELSE &
[15] SET PID=%@SMPEEK[%Hndl,0,4] &
[16] IFF %PID == %_PID THEN &
[17] SET RtnC=%@SMCLOSE[%OHndl] &
[18] SET RtnH=%@SMPOKE[%Hndl,4,4,0] &
[19] SET RtnP=%@SMPOKE[%Hndl,0,4,0] &
[20] ENDIFF &
[21] SET RtnC=%@SMCLOSE[%Hndl] &
[22] SET Hndl=0 &
[23] ENDIFF &
[24] ECHO %Hndl &
[25] ENDLOCAL
Line 1/25: Protect variables
Line 2: Open the shared memory for the semaphore.
Line 3: Get the Shared Memory Handle that is currently holding the semaphore.
Line 4: If it is zero, there is is no handle holding the semaphore.
Line 5: Place the current Shared Memory Handle into the semaphore.
Line 6: Wait a period of time, this may vary depending on how fast your
computer is.
See comments below for more detail on why this is done.
Line 7: Read back the Shared Memory Handle back from Shared Memory.
Line 8: Has the handle changed?
See comments below for more detail on why this is done.
Line 9: If the handle has changed, we have lost the semaphore, close the
shared memory.
Line 10: Zero the Handle for return value in line 24.
Line 12: We retained the semaphore, store the process ID in the
semaphore.
Line 15: The handle in the semaphore is not empty, some process is
holding the semaphore. Get the process ID of the process
holding the semaphore.
Line 16: Is the process holding the semaphore the current process?
Line 17: Close the Share Memory Handle used originally to hold the
semaphore
Line 18: Zero out the semaphore's Shared Memory, this is necessary
because another process could have already opened access to
the semaphore in line 2.
Line 19: Zero out the semaphore's Shared Memory.
Line 21: Zero the Handle for return value in line 24.
Line 24: Return a value to the @execstr, this is either zero or the current
handle to the semaphore's shared memory.
Comment:
I originally required semaphores for critical sections within TCC's event handlers for
monitors. With FOLDMONITOR, I was get multiple event within a very short period of time.
In fact the semaphore itself was prone to problems where multiple processes could get
to line 5 at the same time. This could mean that more than one process could hold the
semaphore. Line 6 to 8 prevents this, basically the last of these processes to get to
line 5 gets to hold the semaphore.
Usage:
I usually use the semaphores as follows:
DO WHILE %@Semaphore[Event1] == 0 (DELAY /M 1)
DO WHILE %@Semaphore[Event2] == 0 (DELAY /M 1)
IFF %@Semaphore[Event1] == 0 THEN
REM
REM Start Critical Section
REM
IFF %@Semaphore[Event2] != 0 THEN
Echo Error on Semaphore Event2
ENDIFF
ELSE
Echo Error on Semaphore Event1
ENDIFF
Last edited: