Skip to content

Instantly share code, notes, and snippets.

@programminghoch10
Last active September 7, 2025 11:52
Show Gist options
  • Select an option

  • Save programminghoch10/7b240002e3ac645fdb01478619e7bf5c to your computer and use it in GitHub Desktop.

Select an option

Save programminghoch10/7b240002e3ac645fdb01478619e7bf5c to your computer and use it in GitHub Desktop.
Simple bash script parallelization using semaphores
#!/bin/bash
SEMPATH="/tmp"
SEMNAME=""
semtake() {
local name="$1"
[ -z "$name" ] && echo "Missing semaphore name!" && return 1
local j="$2"
[ -z "$2" ] && j=$(nproc)
[ -n "$SEMNAME" ] && echo "Already have $SEMNAME" && return 1
while true; do
for i in $(seq 1 $j); do
SEMNAME=".semlock-$name-$j-$i"
mkdir "$SEMPATH/$SEMNAME" 2>/dev/null && break 2
done
sleep 1
done
trap semgive EXIT
}
semgive() {
[ -z "$SEMNAME" ] && return
rmdir "$SEMPATH/$SEMNAME" &>/dev/null || true
SEMNAME=""
}
#!/bin/bash
[ -z "$(command -v inotifywait)" ] && echo "inotify-tools need to be installed for $0 to work!" >&2 && return 1
SEMPATH="/tmp"
[ ! -d "$SEMPATH" ] && echo "$SEMPATH is not a valid directory" >&2 && return 1
! (return 0 2>/dev/null) && echo "$0 can only be sourced, not executed" >&2 && exit 1
#SEMNAME=""
#SEMNAMEID=""
semtake_pool() {
local SEMNAME="$1"
local j="$2"
for i in $(seq 1 "$j"); do
SEMNAMEID="$i"
mkdir "$SEMPATH/$SEMNAME-$SEMNAMEID" 2>/dev/null || continue
return 0
done
unset SEMNAMEID
return 1
}
semtake() {
local name="$1"
[ -z "$name" ] && echo "Missing semaphore name!" >&2 && return 1
local j="$2"
[ -z "$2" ] && j=$(nproc)
[ -n "$SEMNAMEID" ] && echo "Already have $SEMNAME" >&2 && return 1
SEMNAME=".semlock-$name"
until semtake_pool "$SEMNAME" "$j"; do
local i
i="$(find "$SEMPATH" -maxdepth 1 -type d -name "$SEMNAME-wait-*" 2>/dev/null | sed 's/^.*-\([[:digit:]]*\)$/\1/' | sort -n | tail -1)"
[ -z "$i" ] && i=0
local SEMWAITNAME
while true; do
SEMWAITNAME="$SEMNAME"-wait-$i
i=$((i+1))
mkdir "$SEMPATH"/"$SEMWAITNAME" &>/dev/null || continue
break
done
inotifywait --quiet --quiet --event delete_self "$SEMPATH"/"$SEMWAITNAME"
rmdir "$SEMPATH"/"$SEMWAITNAME" &>/dev/null || true
done
trap semgive EXIT
}
semgive() {
[ -z "$SEMNAME" ] && return
[ -z "$SEMNAMEID" ] && return
rmdir "$SEMPATH"/"$SEMNAME"-"$SEMNAMEID" &>/dev/null || true
unset SEMNAMEID
local i
i="$(find "$SEMPATH" -maxdepth 1 -type d -name "$SEMNAME-wait-*" 2>/dev/null | sed 's/^.*-\([[:digit:]]*\)$/\1/' | sort -n | head -1)"
[ -z "$i" ] && return
local SEMWAITNAME
local waiter
for waiter in "$SEMPATH"/"$SEMNAME"-wait-*; do
SEMWAITNAME="$SEMNAME"-wait-$i
i=$((i+1))
rmdir "$SEMPATH"/"$SEMWAITNAME" &>/dev/null || continue
break
done
unset SEMNAME
}
@programminghoch10
Copy link
Author

Reserved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment