Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #
- # a single temporary directory with one writer and 50 readers
- # the writer:
- # - writes 1000 sequential numbers to files in the directory
- # - then writes 50 "quit{0..49}" files
- # each reader:
- # - attempts to read the content of a file in that directory
- # - prints it to stdout
- # - repeats these three steps until nothing remains to be done
- # and it sees a "quit"
- #
- numReaders=50
- numNums=1000
- dir="$(mktemp -d)"
- IFS=$'\n' # don't split on whitespace, simplifies arrays and loops
- # Finds files to process. Ignores temporary files from mktemp and
- # quit messages
- find_nums()
- {
- find "$dir" -mindepth 1 \! \( -name 'quit*' -o -name 'tmp.*' \)
- }
- # launch readers
- for (( i=0; i<numReaders; ++i )); do
- #
- # launch a background sub-shell for each reader
- #
- (
- while true; do
- tmp="$(mktemp --tmpdir="$dir")"
- declare -a nums=( $(find_nums) )
- for num_file in "${nums[@]}"; do
- # renames the file. Thisis an atomic operation and will
- # only succeed for one reader
- mv "$num_file" "$tmp" 2>/dev/null || continue
- num="$(cat "$tmp")"
- # now actually process the file content
- echo "$BASHPID got $num"
- done
- unlink "$tmp"
- sleep 0.1
- if (( ${#nums[@]} > 0 )); then
- continue
- fi
- # no nums, check for quits
- quits=( $(find "$dir" -name 'quit*') )
- if (( ${#quits[@]} == 0 )); then
- continue
- fi
- # got at least one quit. Check again that there are no nums
- # remaining to rule out race condition
- nums=( $(find_nums) )
- if (( ${#nums[@]} > 0 )); then
- continue
- fi
- for quit in "${quits[@]}"; do
- # for quit we don't need the content. unlink is also
- # atomic and will only succeed for one reader
- if unlink "$quit" 2>/dev/null; then
- echo "$BASHPID is done"
- break 2
- fi
- done
- done
- ) &
- done
- #
- # Launch one writer
- #
- for(( i=0; i < numNums; ++i )); do
- # the content has be written to the file before it gets a name
- # that a reader might find and process. So use a temporary file
- # and then rename it
- tmp="$(mktemp --tmpdir="$dir")"
- printf '%04d\n' "$i" >"$tmp"
- mv "$tmp" "$dir/$i"
- done
- for(( i=0; i < numReaders; ++i )); do
- touch "$dir/quit$i"
- done
- echo "Writer finished"
- wait # for readers to finish
- # don't remove the directory before all readers are done
- rmdir "$dir"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement