Jump to content

What is the perfect use for the Semaphore?


Recommended Posts

QUOTE (BrokenArrow @ Nov 16 2008, 10:53 AM)

I really can't see what you can do with a Semaphore that you couldn't do with a local, global, or a Notifier. Does anyone here commonly use them?

Semaphores are ideal for enforcing mutually exclusive access (i.e. locking and unlocking) to a shared resource (global data store, communication pipes/sessions, instruments, etc.). For one great example, see:

"LabVIEW for Everyone", 3rd edition >> Appendix D, "LabVIEW Object-Oriented Programming" >> Semaphored Data Store (pages 912-917)

Semaphores are rarely used, casually, in LabVIEW programming. However, they are extremely useful in certain situations.

Link to comment

QUOTE (Jim Kring @ Nov 16 2008, 01:27 PM)

Semaphores are ideal for enforcing mutually exclusive access (i.e. locking and unlocking) to a shared resource (global data store, communication pipes/sessions, instruments, etc.).

Perfect explination Jim - the term "mutual exclusion" is the important one, and the OO example was the first one that came to my mind too. Another example is instrument control: say you have one VISA serial instrument that you write commands to and get results from - and two (or more) parts of your software that call it. You can wrap command/response pairs in a semaphore so the different areas of your software don't clash (eg: command from A, then B sends a command before A has queried it's response - very messy :) ).

Link to comment

QUOTE (crelf @ Nov 16 2008, 11:08 AM)

Yes, and in "old school" lingo these uses are known as a "MUTEXx" for "MUTually EXclusive" code section. cf: http://en.wikipedia.org/wiki/Mutual_exclusion

Now for a more complex definition (somewhat outside the ken of LV), the word semaphore has come to be used for multi-threaded code whereas mutex has colloquially been reserved for single-threaded code; although my sense of that history of use -- FWIW -- is that those who use semaphore for multi-threaded code just forgot the origin and historical use of mutex. cf: http://doc.trolltech.com/qq/qq11-mutex.html

and all of that is probably WAY more than you wanted to hear.

in re: to

"Q: What's a semaphore? A: ...

I Googled "sema" but couldn't find anything useful."

That's true, as far as it goes, but in the US the right answer is "to haul things and keep the Teamsters from becoming either a motorcycle gang or an ABBA cover group", and that's because a semi is an 18-wheel truck.... ;-

Link to comment

QUOTE (Jim Kring @ Nov 16 2008, 02:27 PM)

Semaphores are rarely used, casually, in LabVIEW programming. However, they are extremely useful in certain situations.

Thanks Jim,

Understood, that's obviously why the few times I've used them "casually" I ended up replacing them with globals, likely because I was using them (the semaphores) where they were not required. However, one example of where I used a semaphore and eventually changed it to a global was in a program that did exactly what crelf described. I had a parallel loop where two VISA resources had a slim chance of causing a train wreck. I ended up just using a global boolean. For the sake of argument this boolean was called "Don't Run". The boolean, wired to a case statement, was simply lit up appropriately to avoid dual access to the resource. Now, granted, this is a typical use of a "variable" which doesn't follow the dataflow paradigm etc etc, but it worked like a champ and I didn't have VI's that use code interface nodes (semaphores) hanging all around.

Jim, is that example available electronically when you buy the book? I can't learn anything from the shipped semaphore examples. In fact, those examples only cement my bias.

Link to comment

QUOTE (BrokenArrow @ Nov 16 2008, 12:53 PM)

I really can't see what you can do with a Semaphore that you couldn't do with a local, global, or a Notifier. Does anyone here commonly use them?

I've learned to use User/Registered events in lieu of semaphores, locals, globals, notifiers, etc. Simple and elegant.

Link to comment

QUOTE (BrokenArrow @ Nov 16 2008, 05:26 PM)

Thanks Jim,

Understood, that's obviously why the few times I've used them "casually" I ended up replacing them with globals, likely because I was using them (the semaphores) where they were not required. However, one example of where I used a semaphore and eventually changed it to a global was in a program that did exactly what crelf described. I had a parallel loop where two VISA resources had a slim chance of causing a train wreck. I ended up just using a global boolean. For the sake of argument this boolean was called "Don't Run". The boolean, wired to a case statement, was simply lit up appropriately to avoid dual access to the resource. Now, granted, this is a typical use of a "variable" which doesn't follow the dataflow paradigm etc etc, but it worked like a champ and I didn't have VI's that use code interface nodes (semaphores) hanging all around.

Jim, is that example available electronically when you buy the book? I can't learn anything from the shipped semaphore examples. In fact, those examples only cement my bias.

If I understand what you're posting, you essentially created a functional mutex without using the semaphore code in LV.

And FWIW -- and I'm probably wrong on this -- but I thought that the CINs were dropped for semaphores in 8.5, if not sooner.

Link to comment

Instead of semaphore I normally use FGV (Functional Global Variable) or OO methods; the fact that people like to use other method than semaphore is mainly because the structure of semaphore i think.

You have to use couple of vis in your program and all the wiring to connect those vis make things more crowded sometimes. I agree that this structure can be a redundancy in the next version of LV.

Link to comment

Minh,

Yep, a LV2 global, like OpenG's "Data Changed" is a great tool to prevent train wrecks. I agree that the structure of the semaphore is strange. Why on earth should there be a "Not a Semaphore.vi" if the structure were not conducive to abuse and mixing with other things?

Val,

Good point! It looks like 8.6 has replaced the CIN's with Queues and other dodgy bits, and 8.5 uses CIN's. Even NI agrees that it was never necessary to begin with! :D (kidding).

Link to comment

QUOTE (BrokenArrow @ Nov 17 2008, 09:13 AM)

Minh,

Yep, a LV2 global, like OpenG's "Data Changed" is a great tool to prevent train wrecks. I agree that the structure of the semaphore is strange. Why on earth should there be a "Not a Semaphore.vi" if the structure were not conducive to abuse and mixing with other things?

Val,

Good point! It looks like 8.6 has replaced the CIN's with Queues and other dodgy bits, and 8.5 uses CIN's. Even NI agrees that it was never necessary to begin with! :D (kidding).

Semaphores are very useful for controlling access to shared files. If parts of the code require continual upating of a file while another must read from that same file, a semaphore can be sued to prevent issue with the file pointer of the "read" to screw up the file writing. Under many conditions I can avoid the semaphore by putting the file I/O in an Action Engine (that is automatically protected using a mechanism very similar to semaphores) but if some of the File I/O is CPU intensive, I may be designing in additional bottle knecks. By using Semaphores to protect the file access, I can reduce the bottle-kneck to just the File I/O and nothing else.

Note: Any shared resource can be protected the same way the file is protected.

Ben

Link to comment

Also note that global variables (not FGVs) do NOT give you the same protection a semaphore does! It's very possible that two or more parts of the application could get control of the shared resource at the same time. This is known as a race condition.

For example, suppose you have a boolean global called Don't Write that you set to true while one part of the code is writing to a shared file. If that global is true, other parts of the program don't write anything and wait for the global to be false. Sounds safe? Wrong... It's possible (and in the long run probable) that two parts of the program could check the global at relatively the same time, both read false, and both set the global to true and start writing. The worst part of this is that it rarely happens. That's bad because now you have an intermittent bug that's difficult to reproduce, and therefore difficult to debug and difficult to prove you've fixed it later.

The only fix to using a global variable for protection would be to put semaphores around the use of the global variable, but then you've pretty much ruined the use case for using a global at all. Hope this helps!

Link to comment

Ben and raggle,

Very good points. And I've had each issue, resolved one way or another, when if fact the Semaphore would have been ideal. I'm not trying to be anti-semaphoric, I just needed a nudge. Thanks! :worship:

This is deja-vu all over again. Five+ years ago, I was having a similar battle overcomming a bias against Notifiers. Now, I can't live without them.

OK, I have three globals on my recent project... "Inhibit Port Acess", "Don't Write Now", and "Let The Other Loop Catch Up Before Proceeding". Time to change these to Semaphores. Actually, that last one sounds more like a Rendezvous. :rolleyes:

Link to comment

I understood semaphores a bit better after learning Italian. The Italian word for traffic light is semaforo, which tranlsates directly to semaphore. If you look at the intersection as your shared resource, the traffic light is the semaphore controlling access to that resource. It only allows access in a safe way to everyone involved. (I'm not sure if data ever runs red lights though)

Link to comment

QUOTE (TobyD @ Nov 17 2008, 12:10 PM)

I understood semaphores a bit better after learning Italian. The Italian word for traffic light is semaforo, which tranlsates directly to semaphore. If you look at the intersection as your shared resource, the traffic light is the semaphore controlling access to that resource. It only allows access in a safe way to everyone involved. (I'm not sure if data ever runs red lights though)

Hence the traffic light icons on the Semaphores.

If a semaphore is a traffic light in LA where if you run it you die, then the global variable implementation of a semaphore is a stop sign, partially obscured by weeds and limbs, on an abandoned contry road where race conditions exist freely.

Link to comment

QUOTE (BrokenArrow @ Nov 17 2008, 11:19 AM)

... then the global variable implementation of a semaphore is a stop sign, partially obscured by weeds and limbs, on an abandoned contry road where race conditions exist freely ...

... and a troll that live under a nearby bridge wakes up and repaints the sign depending on the phase of the moon and the house in which you will find Mars.

Link to comment

QUOTE (TobyD @ Nov 17 2008, 08:10 AM)

I understood semaphores a bit better after learning Italian. The Italian word for traffic light is semaforo, which tranlsates directly to semaphore. If you look at the intersection as your shared resource, the traffic light is the semaphore controlling access to that resource. It only allows access in a safe way to everyone involved. (I'm not sure if data ever runs red lights though)

If it does then it's not data but an object... ;-)

There is "Not A Semaphore" for the simple reason (I assume) that one might want to test for its existence. This is similar structurally, is it not, to having "Not A Refnum..." and such.

Link to comment

QUOTE (Val Brown @ Nov 17 2008, 10:13 AM)

There is "Not A Semaphore" for the simple reason (I assume) that one might want to test for its existence. This is similar structurally, is it not, to having "Not A Refnum..." and such.

Yes, especially since the "Not A Refnum" function does not handle Semaphores (or "classic", non-native Queues and Notifiers).

Link to comment

This is just a race condition, but I wanted to give a more concrete example. Let's say you have some kind of cluster or array which is modified in different threads of your application. You may have to unbundle or index it, replace the element, rebundle it, and wire it back into the global (or notifier or lv2 global or whatever). Between the unbundle and the rebundle, you have to make sure that no other thread can start the same process of unbundling, or else one of the copies will be stale and be victim of a race condition.

The normal way to fix this is to wrap the operation in a subvi so you can take advantage of the blocking behavior of subvi calls. However, this means the subvi has to know about every type of data you might want to replace in this global thing, which may lead to running out of terminal pane connectors, and generally ugly code. The other alternative is protecting the updates with a semaphore.

Link to comment

QUOTE (TobyD @ Nov 17 2008, 08:10 AM)

I understood semaphores a bit better after learning Italian. The Italian word for traffic light is semaforo, which tranlsates directly to semaphore. If you look at the intersection as your shared resource, the traffic light is the semaphore controlling access to that resource. It only allows access in a safe way to everyone involved. (I'm not sure if data ever runs red lights though)

The stop light is a recent adaptation of what the semaphore was originally: viz, a means of communicating by the relative positions of "arms", either mechanical or human. Like Morse Code each position meant a single letter. This was a means of communicating between ships in a squadron, esp during battle conditions, and it's use for those purposes dates back several hundred years. The basis of the "stop" was that the communication protocol was not duplex. Each communicator had to finish their entire message and then STOP in order to receive the reply. The "shared resource" was the communication "channel" between the vessels at sea. This means of communication had the advantage that messages could be sent more quickly than via "flags" being set. Flag-based communication was essentially what we would call today a notifier.

This arrangement of communicating by the position of "arms" was taken over by the railroads where early "blocking signals" had semaphore "arms" that indicated whether a particular section of track was free to access ("go" pointing straight up) or currently in used ("do not go, but wait" horizontal across the track) or about to be used ("proceed to siding to wait there" forty-five degree angle). Many early automobile traffic control devices used arms. Over time those devices were replaced by devices using lights (the familiar red, yellow, green) both for automobile traffic but also for railroads, with the "caution" position being moved to the middle signaling position.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.