Advertisement
homer512

Bash message passing

Mar 25th, 2014
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 2.39 KB | None | 0 0
  1. #
  2. # a single temporary directory with one writer and 50 readers
  3. # the writer:
  4. #    - writes 1000 sequential numbers to files in the directory
  5. #    - then writes 50 "quit{0..49}" files
  6. # each reader:
  7. #    - attempts to read the content of a file in that directory
  8. #    - prints it to stdout
  9. #    - repeats these three steps until nothing remains to be done
  10. #      and it sees a "quit"
  11. #
  12. numReaders=50
  13. numNums=1000
  14.  
  15. dir="$(mktemp -d)"
  16. IFS=$'\n' # don't split on whitespace, simplifies arrays and loops
  17.  
  18. # Finds files to process. Ignores temporary files from mktemp and
  19. # quit messages
  20. find_nums()
  21. {
  22.     find "$dir" -mindepth 1 \! \( -name 'quit*' -o -name 'tmp.*' \)
  23. }
  24. # launch readers
  25. for (( i=0; i<numReaders; ++i )); do
  26.     #
  27.     # launch a background sub-shell for each reader
  28.     #
  29.     (
  30.     while true; do
  31.         tmp="$(mktemp --tmpdir="$dir")"
  32.         declare -a nums=( $(find_nums) )
  33.         for num_file in "${nums[@]}"; do
  34.         # renames the file. Thisis an atomic operation and will
  35.         # only succeed for one reader
  36.         mv "$num_file" "$tmp" 2>/dev/null || continue
  37.         num="$(cat "$tmp")"
  38.         # now actually process the file content
  39.         echo "$BASHPID got $num"
  40.         done
  41.         unlink "$tmp"
  42.         sleep 0.1
  43.         if (( ${#nums[@]} > 0 )); then
  44.             continue
  45.         fi
  46.         # no nums, check for quits
  47.         quits=( $(find "$dir" -name 'quit*') )
  48.         if (( ${#quits[@]} == 0 )); then
  49.             continue
  50.         fi
  51.         # got at least one quit. Check again that there are no nums
  52.         # remaining to rule out race condition
  53.         nums=( $(find_nums) )
  54.         if (( ${#nums[@]} > 0 )); then
  55.             continue
  56.         fi
  57.         for quit in "${quits[@]}"; do
  58.         # for quit we don't need the content. unlink is also
  59.         # atomic and will only succeed for one reader
  60.             if unlink "$quit" 2>/dev/null; then
  61.                 echo "$BASHPID is done"
  62.                 break 2
  63.             fi
  64.         done
  65.     done
  66.     ) &
  67. done
  68. #
  69. # Launch one writer
  70. #
  71. for(( i=0; i < numNums; ++i )); do
  72.     # the content has be written to the file before it gets a name
  73.     # that a reader might find and process. So use a temporary file
  74.     # and then rename it
  75.     tmp="$(mktemp --tmpdir="$dir")"
  76.     printf '%04d\n' "$i" >"$tmp"
  77.     mv "$tmp" "$dir/$i"
  78. done
  79. for(( i=0; i < numReaders; ++i )); do
  80.     touch "$dir/quit$i"
  81. done
  82.  
  83. echo "Writer finished"
  84. wait # for readers to finish
  85.  
  86. # don't remove the directory before all readers are done
  87. rmdir "$dir"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement