Skip to content

Instantly share code, notes, and snippets.

@brianloveswords
Last active April 8, 2021 22:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianloveswords/7ba95bb801b30a58045290ac6a3505e2 to your computer and use it in GitHub Desktop.
Save brianloveswords/7ba95bb801b30a58045290ac6a3505e2 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
function example() {
set -o errexit
set -o nounset
## only needed for the example
local worktime=0
# how many concurrent operations to perform
with-concurrency "$(getcores)"
## the `seq` would be replaced with whatever you're looping over
for x in $(seq 20); do
## just for the example, not needed in your implementation
local naptime
naptime=$(randbetween 1 10)
worktime=$((worktime + naptime))
## your job would go here
takelock && (
echo "doing job #${x}; working for ${naptime}s"
sleep "${naptime}"
releaselock
) &
done
wait
echo "completed ${worktime}s of work"
}
## implementation
trap "cleanup" EXIT SIGABRT SIGINT
function cleanup() {
set +o nounset
if [[ -n ${__LOCKFILE} && -f ${__LOCKFILE} ]]; then
set -o nounset
rm -f "${__LOCKFILE}"
for jobid in $(jobs -p); do
ps "${jobid}" >/dev/null && kill "${jobid}"
done
fi
}
function debug() {
echo 1>&2 "DEBUG: ${*}"
}
function tmpfile() {
head -c 32 /dev/random | md5
}
function with-concurrency() {
## purposely NOT local so these can escape their scope
__LOCKMAX="${1}"
__LOCKFILE=${TMPDIR}/$(tmpfile)
function readlock() {
if [[ ! -f ${__LOCKFILE} ]]; then
exit 1
fi
cat "${__LOCKFILE}"
}
function takelock() {
if [[ ! -f ${__LOCKFILE} || ${__STOPPED} -eq 1 ]]; then
exit 1
fi
while true; do
if [[ ! $(readlock) -lt ${__LOCKMAX} ]]; then
sleep 1
else
echo $(($(readlock) + 1)) >"${__LOCKFILE}"
debug "taking lock"
break
fi
done
}
function releaselock() {
if [[ ! -f ${__LOCKFILE} ]]; then
exit 1
fi
echo $(($(readlock) - 1)) >"${__LOCKFILE}"
debug "released lock"
}
echo 0 >"${__LOCKFILE}"
}
function randbetween() {
# macOS or FreeBSD only
jot -r 1 "${1}" "${2}"
}
function getcores() {
getconf _NPROCESSORS_ONLN 2>/dev/null || 8
}
time example "$(getcores)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment