Click for: WEBPAGE INDEX

web page created Wednesday 25th February 2004 evening

AmigaOS semaphores are a bit tricky to program, the example here which is really a simplest possible usage was quite an effort to get right.

Download the archive, the program is semaphores. Using the program is straightforward, writing it is not. Parallel programming is fraught with difficulties and sometimes its better to just write a unitasking unithreaded program because its more likely to be correct! Anyway one strategy to deal with the trickiness of such things is to try and contain the tricky stuff in subroutines and only access the mechanism through the subroutines, this is what I have done here, the difficulties are contained within semaphores so when you use it you are protected from the "issues".

Its a bit like how the Amiga has pre-emptive multitasking but most user programs are unitasking, ie the programmer is shielded from the problems of multitasking code.

The best way to understand semaphores and mutexing in general is via some experiments!:

============= Experiment 1 =============

Open 3 shells and have them all visible say A, B and C.

In shell A type:

semaphores hello e

this will return immediately, but has in fact obtained an exclusive lock on a public AmigaOS Semaphore called hello. You can have as many as you want with any name. This program requires the names to be made of characters a-z, A-Z, 0-9, _,

Now in shell B type:

semaphores hello e

this doesnt return! it has been queued up to wait for the semaphore "hello". Likewise in shell C type the same, this will also be waiting. This is all because exactly one task can possess an exclusive lock on a particular semaphore.

Now in shell A, type:

semaphores hello u

This unlocks the Semaphore, ie relinquishes it, you will now notice that shell B immediately returns to a prompt but C doesnt! This is because B is next in the queue. B now has the exclusive lock.

Now in shell B, type:

semaphores hello u

and shell C will immediately return: its now C's turn.

Try typing semaphores hello u in shell B and see what happens.

Lastly type semaphores hello u in shell C. The semaphore "hello" is now fully relinquished, try typing semaphores hello u again from any of the 3 shells and see what happens.

If you type eg

semaphores ?

it will tell you all the options. The option s gives you a shared lock and E attempts to get an exclusive lock without waiting. If the E attempt fails you get a "warn" return for "if warn" in shell scripts.

Try experimenting with eg s in a similar manner to see what it is about.

=========== Experiment 2 =========

Find a large directory say xyz: that takes a long time for the command

list xyz: all

Now create a script file expt2

semaphores expt2 e
list xyz: all
semaphores expt2 u

Now open 2 shells A and B, in each type

expt2

You will see that the second shell waits till the first shell has completely finished before it starts. This shows how semaphores can be used as a queue-up mechanism for shell scripts.

Now I show 2 practical uses of all this:

======= assign counts done correctly ========

create a script file assign_plus:

.k name___,dirlist___
.bra {
.ket }

semaphores {name___} e ; obtain exclusive lock

			; because this is not Forbid(); we can take
			; as long as we like!

if not exists env:{name___}
echo "0" to env:{name___} noline
endif

eval ${name___} + 1 to env:{name___}  ; counts no of times assign is done

assign {name___}: {dirlist___}

semaphores {name___} u ; 

create another script file assign_minus:

.k name___ 
.bra {
.ket }

semaphores {name___} e ; obtain exclusive lock

			; because this is not Forbid(); we can take
			; as long as we like!

if not exists env:{name___}
echo "assign {name___}: doesnt exist"
quit 5 ; warn
endif

eval ${name___} - 1 to env:{name___}  ; counts no of times assign is done

if ${name___} eq 0
assign {name___}:   ; only remove the assign when count reaches 0
endif 

semaphores {name___} u ; 

Example usage of the scripts is:

assign_plus  xyz "ram: df0: cd0:  Workbench:s"

	; assigns xyz: to the list ram: df0: etc

assign_minus xyz ; to undo the above,

============ text editor problem example ========

I often have many copies of Memacs running with each one showing a different file. eg 1 Memacs may have some C, another a header file, another some assembler. If I am editing several files then its possible to lose track of which files are currently being edited. So if you are not careful you might load some file twice and thus be making changes to the wrong copy! So when you save and exit some of your changes are lost.

To get around this you need a script that prevents a file being editted twice. A naive script could be:

.k name___
.bra {
.ket }

if exists "{name___}.flag"
echo "*"{name___}*"" is already being editted, quitting,
quit 5 ; warn
endif

echo "hello" to "{name___}.flag"

Memacs "{name___}"

delete "{name___}.flag"

This looks ok, but the problem is that if 2 scripts were run in quick succession you would end up with 2 copies running because the second script looked for {name___}.flag before the first script created it.

What is needed here is an "indivisible read modify write", the simplest way to do it is via 1 global Semaphore called Memacs

.k name___
.bra {
.ket }

semaphores Memacs e

if exists "{name___}.flag"
echo "*"{name___}*"" is already being editted, quitting,
semaphores Memacs u
quit 5 ; warn
endif

echo "hello" to "{name___}.flag"

semaphores Memacs u

Memacs "{name___}"

delete "{name___}.flag"

I think this is now ok, although Memacs is a global Semaphore, it is only locked for a small interval of time, with the lockers queuing up.

Being able to queue up shell scripts is a useful facility eg sometimes its better for copying actions to be one at a time because parallel copying to or from a given volume can be exceedingly inefficient as the disk heads have to keep zig zagging.

Semaphores and Mutexes are a bit like a local anaesthetic, you just create local paralysis not global. If you experiment with the above semaphores program, you will understand why they call it a Semaphore, it really feels like the 1 shell is "signalling" the other. The term is very appropriate but only when you have seen it in action, not when you read about it!
Get a GoStats hit counter