1. 程式人生 > 實用技巧 >shell 多程序(併發)

shell 多程序(併發)

#!/bin/bash

# 接受訊號2(ctrl+C)
# 關閉fd 6的繫結
# 注意:繫結時可以用 exec <> fifofile; 
# 但關閉時必須分開寫:exec 6>&-和exec 6<&- 是關閉fd6
trap "exec 6>&-; exec 6<&-; exit 0" 2

# 管道檔名
tempfile="temp.$$"

# 建立有名管道
# 管道的特點:
# 1. 如果管道中沒有資料,則讀管道資料的操作會阻塞,直到管道內寫入資料
# 2. 管道內有資料,如果沒有讀取操作也會阻塞,直到讀取後才會終止這一操作
mkfifo ${tempfile}

# 繫結檔案操作符為管道
exec 6<>${tempfile}

# fd6已繫結成為管道,不再需要管道檔案,可直接刪除掉
rm -f ${tempfile}

# 併發執行執行緒數
tnum=10

preip="192.168.100."

# 對檔案操作符進行寫入操作,通過for迴圈寫入$tnum個空行,即為後臺執行緒數量
for ((i=1; i<=$tnum; i++)); do
{
  echo >&6
}
done

for ip in $(seq 2 254); do
{
  # 從檔案操作符讀取管道中的一個空行
  read -u 6
  {
    # 併發操作程式碼塊
    sleep 1
    ping -q -c2 -W1 "${preip}$ip" &>/dev/null
    if [ $? -eq 0 ]; then
      echo -e "\033[32m${preip}$ip is alive.\033[0m"  
    else
      echo -e "\033[31m${preip}$ip is down.\033[0m"  
    fi
    
    # 重點:讀取完一個空行後,重新向檔案操作符寫入一個空行,
    # 否則當$tnum個任務放入後臺後,由於操作符中沒有可讀取的空行,導致read -u 6阻塞
    echo >&6
  }&  # 將任務放入後臺執行
}
done

# 等待所有執行緒執行完畢,避免主程序提前退出
wait

# 關閉檔案操作符的讀寫繫結
exec 6>&-
exec 6<&-