Skip to content

Instantly share code, notes, and snippets.

@ansemjo
Last active July 6, 2016 09:50
Show Gist options
  • Save ansemjo/de614968cbf3ed058cb88f8ed9df6381 to your computer and use it in GitHub Desktop.
Save ansemjo/de614968cbf3ed058cb88f8ed9df6381 to your computer and use it in GitHub Desktop.
#!/bin/env bash
# The MIT License (MIT)
#
# Copyright (c) 2016 Anton Semjonov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# This is an example script on how to use mutexes in bash.
# There is no 'real' mutex available in bash, because a mutex would need
# a really atomic operation with support from the cpu itself. The closest
# thing to an atomic operation appears to be 'mkdir' which succeeds and
# creates a folder or fails if it exists. Additionally, use signals and
# traps to avoid busy waiting. This is the result ...
trap "kill -SIGTERM -$$" SIGINT
iterations=5
function mutex {
# mutex (new|acquire|release) [$lock, iff !new]
subcommand=${1:?(new|acquire|release)}
case $subcommand in
new)
mktemp --tmpdir --directory mutex-XXXXXXXXXXXXXXXXXXX;;
acquire)
lock=${2:?specify lock!}
while ! mkdir "$lock" &>/dev/null; do
kill -SIGSTOP $BASHPID; done;;
release)
lock=${2:?specify lock!}
rm -r "$lock";
kill -SIGCONT -$$;;
*)
return 1;;
esac
}
function say { echo -e "${colorspec:+\e[${colorspec}m}${name:+$name }${child:+$(progress $iteration/$iterations) }\e[0m$@"; }
function progress { #give: 5/7 or 99/100 etc
have=${1%%/*}
length=${1##*/}
let left="length - have"
L="▐"; R="▌";
F="▓"; E="░";
printf "$L%${have}s" | sed "s, ,$F,g"
printf "%${left}s$R" | sed "s, ,$E,g"
}
function child {
name="${1:?'I need a name!'}"
colorspec="${2:-1}"
child=yes
iteration="0"
say "new child. PID $BASHPID, ProcessGroup $$"
until test "$iteration" -ge "$iterations"; do
mutex acquire "$uselock"
let "iteration++"
say working ...
say "$iteration/$iterations$(test "$iteration" = "$iterations" && echo " DONE!")"
mutex release "$uselock"
done
}
#######################################################################
name="MASTER:"
colorspec="1"
uselock=$(mutex new)
say "Set mutex: '$uselock'"
# SPAWNING ...
say "spawning children ..."
childcolorspec=31
for childname in CHILD_{A..F}; do
child "$childname" "$childcolorspec" &
let "childcolorspec++"
done
sleep 1
for sec in 3 2 1; do say "$sec ..."; sleep 0.5; done
say "releasing mutex ..."
mutex release "$uselock"
wait
say "all children exited. FINISHED!"
mutex release "$uselock" &>/dev/null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment