How to create a semaphore in bash

Contents

Bash Shell

Are you developing a multithreaded application? Sooner or later, you will probably need to use a traffic light. In this article, you will learn what a traffic light is, how to create / practice one in bash and more.

What is a Traffic lights?

A semaphore is a programming construct used in computer programs that employ multiple threads of processing. (computer processing threads running source code from the same program or set of programs) to achieve exclusive use of a common resource at any given time. . Said in a much simpler way, think of this as “one at the same time, please”.

A traffic light was first defined in the late 1990s. 1960 by the late computer scientist Edsger Dijkstra from Rotterdam in the Netherlands. You've probably used traffic lights frequently in your life without specifically realizing that you were doing it!!

Stay in the Netherlands for a while, a country full of small waterways and many movable bridges (called drawbridge in american english), you can see many excellent real world examples of a traffic light; consider the handle of a drawbridge operator: up or down. That handle is the traffic light variable that protects the waterway or highway from accidents. A) Yes, the waterway and roads could be seen as other variables protected by the traffic light.

If the handle is up and the bridge is open, the exclusive use of the intersection water / road is given to the ship or ships passing through the water channel. When the handle is down, the bridge is closed and the exclusive use of the intersection water is given / road to cars passing over the bridge.

The semaphore variable can control access to another set of variables. As an example, the condition of the handle prevents the $cars_per_minute and $car_toll_booth_total_income variables so they are not updated, etc.

We can take the example a little further and explain that when the handle works up or down, both captains of boats in the water and people driving cars and trucks on the road can see a matching light: all operators can read a common variable for a specific state.

Even though the scenario described here is not just a traffic light, but at the same time it is a simple mutex. A mutex is another common programming construct that is very similar to a semaphore, with the additional condition that a mutex can only be unlocked by the same task or thread that locked it. Mutex means “mutually exclusive”.

For this case, this applies to our example, since the bridge operator is the only one with control over our semaphore and mutex up / down. Conversely, if the guardhouse at the end of the bridge had a bridge override switch, we would still have a semaphore configuration, but not a mutex.

Both constructs are used regularly in computer programming when using multiple threads to ensure that only a single procedure or task accesses a given resource at any one time. Some traffic lights can be ultra-fast switching, as an example, when used in multi-threaded financial market trading software, and some can be much slower, they only change state every few minutes, such as when used on an automated drawbridge or at a railroad crossing.

Now that we have a better understanding of traffic lights, let's implement one in Bash.

Implementing a traffic light in Bash: Easy or not?

Implementing a traffic light in Bash is so easy that it can even be done directly from the command line, or so it seems …

Let's start simply.

BRIDGE=up
if [ "${BRIDGE}" = "Down" ]; then echo "Cars may pass!"; else echo "Ships may pass!"; fi
BRIDGE=down
if [ "${BRIDGE}" = "Down" ]; then echo "Cars may pass!"; else echo "Ships may pass!"; be

Example of update command line and output of bridge status

In this code, the variable BRIDGE has our bridge status. When we put it in up, Ships can pass and when we put it in down, cars can pass. At the same time we could read the value of our variable at any point to see if the bridge is truly up or down. The share / common, in this circumstance, is our bridge.

Nonetheless, this example is single threaded and, it is because of that, we never find howhelp the unions situation. Another way to think about this is that our variable can never be up and down exactly at the same time that the code is executed sequentially, in other words, Step by Step.

Another thing to pay attention to is that we do not really control access to another variable (as a traffic light would regularly), so our BRIDGE variable is not truly a true semaphore variable, even when it gets closer.

In summary, as soon as we introduce various threads that can affect the BRIDGE variable we run into problems. As an example, what if, directly after BRIDGE=up command, another thread problems BRIDGE=down which would later result in the message Cars may pass! Exit, even though the first thread would expect the bridge to be up, and actually the bridge is still moving. Dangerous!

You can see how things can quickly get murky and confusing, not to mention complex, when working with enough threads.

The situation where multiple threads try to update the same variable at the same time or at least close enough in time for another thread to mess up the situation (which in the case of drawbridges can take a long time) it is called race condition: two threads competing to update or report some variable or status, with the result that one or more threads may go quite wrong.

We can improve this code a lot by flowing the code in procedures and using a real semaphore variable that will restrict access to our BRIDGE variable depending on the situation.

Creating a bash semaphore

Implement a full multithreaded, make it thread safe (a computing definition to describe software that is thread safe or developed in such a way that threads cannot negatively or incorrectly affect each other when they should not) It is not an easy task. Even a well-written program that uses semaphores is not guaranteed to be absolutely thread-safe..

The more threads there are, and the higher the frequency and complexity of the interactions between threads, race conditions are more likely.

For our little example, we will see the definition of a Bash semaphore when one of the drawbridge operators lowers the bridge handle, indicating that you want to lower the bridge. Avid readers may have noticed the reference to operators instead of operator: now there are several operators who can lower the bridge. In other words, there are multiple threads or tasks running at the same time.

#!/bin/bash

BRIDGE_SEMAPHORE=0

lower_bridge(){  # An operator put one of the bridge operation handles downward (as a new state).
  # Assume it was previously agreed between operators that as soon as one of the operators 
  # moves a bridge operation handle that their command has to be executed, either sooner or later
  # hence, we commence a loop which will wait for the bridge to become available for movement
  while true; do
    if [ "${BRIDGE_SEMAPHORE}" -eq 1 ]; then
      echo "Bridge semaphore locked, bridge moving or other issue. Waiting 2 minutes before re-check."
      sleep 120
      continue  # Continue loop
    elif [ "${BRIDGE_SEMAPHORE}" -eq 0 ]; then   
      echo "Lower bridge command accepted, locking semaphore and lowering the bridge."
      BRIDGE_SEMAPHORE=1
      execute_lower_bridge
      wait_for_bridge_to_come_down
      BRIDGE='down'
      echo "Bridge lowered, ensuring at least 5 minutes pass before next allowed bridge movement."
      sleep 300
      echo "5 Minutes passed, unlocking semaphore (releasing bridge control)"
      BRIDGE_SEMAPHORE=0
      break  # Exit loop
    fi
  done
}

A traffic light implementation in Bash

Here we have a lower_bridge function that will do a number of things. First, suppose another operator recently moved the bridge in the last minute. As such, there is another thread that executes code in a function similar to this call raise_bridge.

Actually, that function has finished raising the bridge, but has instituted a mandatory wait of 5 minutes that all operators agreed in advance and that was encoded in the source code: keep the bridge from going up / come down all the time. At the same time you can see this mandatory wait of 5 minutes implemented in this function as sleep 300.

Then, when that raise_bridge the function is operating, will have set the semaphore variable BRIDGE_SEMAPHORE a 1, the same way we do it in the code here (directly after echo "Lower bridge command accepted, locking semaphore and lowering bridge" command), and – through the first if conditional check in this code: the infinite loop present in this function will continue (ref continue In the code) to loop, with pauses of 2 minutes, As the BRIDGE_SEMAPHORE variable is 1.

As soon as that raise_bridge The show finishes raising the bridge and ends its five-minute suspension, will establish the BRIDGE_SEMAPHORE a 0, allowing our lower_bridge co function starts executing functions execute_lower_bridge and subsequent wait_for_bridge_to_come_down at the same time that we have blocked our traffic light again to 1 to prevent other functions from taking over the bridge.

Nonetheless, There are shortcomings in this code and possible race conditions that can have far-reaching consequences for bridge operators.. Can you see any?

the "Lower bridge command accepted, locking semaphore and lowering bridge" not thread safe.

If another thread, as an example raise_bridge is running at the same time and trying to access the BRIDGE_SEMAPHORE variable, could be (when BRIDGE_SEMAPHORE=0 and both running threads reach their respective echoIt is exactly at the same time that the bridge operators see “The bottom bridge command is accepted, the traffic light is blocked and the bridge is lowered” and “Bridge lift command accepted, the traffic light is blocked and the bridge is raised”. Directly one after the other on the screen! Afraid, ¿no?

Even scarier is the fact that both threads can continue BRIDGE_SEMAPHORE=1, And both threads can continue to run! (There is nothing to stop them from doing it) The reason is that there is not much protection for such scenarios yet. Even though this code implements a semaphore, it is by no means thread safe. As it was told, multi-threaded coding is complex and needs a lot of experience.

Even though the time required in this circumstance is minimal (1-2 lines of code take only a few milliseconds to execute), and given the probably low number of bridge operators, the chance of this happening is very small. Nonetheless, the fact that it is viable is what makes it dangerous. Creating thread safe code in Bash is not an easy task.

This could be further improved, as an example, introducing a pre-lock and / or introducing some kind of delay with a new subsequent verification (even though this will probably require an additional variable) or doing a regular re-check before the actual execution of the bridge. , etc. Another alternative is to make a priority queue or a counter variable that checks how many threads have blocked control of the bridge, etc.

Another commonly used approach, as an example, when running multiple bash scripts that might interact, is to use mkdir O flock as base lock operations. There are several examples of how to implement them available online, as an example, What Unix commands can be used as a semaphore / blocking?.

Ending

In this article, we take a look at what a traffic light is. At the same time we briefly touched on the theme of a mutex. In summary, we analyze the implementation of a semaphore in Bash using the practical example of several bridge operators operating a mobile bridge / drawbridge. At the same time we explore how complex is the implementation of a reliable solution based on traffic lights.

If you enjoyed reading this article, take a look at our claims, errors and crashes: what is the difference? Article.

Subscribe to our Newsletter

We will not send you SPAM mail. We hate it as much as you.