shell模擬“多執行緒”

Federico發表於2017-10-20

  shell中並沒有真正意義上的多執行緒,要實現“多執行緒”可以啟動多個子程式,並將子程式放入後臺執行來模擬多執行緒,最大程度利用CPU效能。

迴圈中執行並行程式碼

#!/bin/bash
date
for i in `seq 1 5`
do
{
    echo "sleep 5"
    sleep 5
} &
done
wait
date

執行結果如下:
Thu Oct 19 19:58:43 CST 2017 sleep 5 sleep 5 sleep 5 sleep 5 sleep 5 Thu Oct 19 19:58:48 CST 2017
由此我們可以看出,所有的for迴圈下的指令都可以同時執行,使用wait命令等待所有子程式結束。

  這樣能夠提供指令碼執行的效率,但是我們又不能無限制的讓這個for迴圈去啟動子程式,所以就需要我們對這個程式數進行設定。

#!/bin/bash
date
trap "exec 5>&-; exec 5 <&-; exit 0" 2
THREAD_NUM=10
tmp_fifofile="/tmp/$$.fifo"
mkfifo "$tmp_fifofile"
exec 5<>"$tmp_fifofile"
rm $tmp_fifofile
for ((i=0;i<$THREAD_NUM;i++));do
    echo
done >&5

for i in `seq 1 50`
do
    read -u5
    {
        sleep 1
    echo "----------"
        echo >&5
    } &
done
wait
exec 5>&-
date

trap "exec 5>&-; exec 5 <&-; exit 0" 2#接收訊號2(Ctrl +C )的操作,並關閉描述符5
THREAD_NUM=10#允許的最大程式數。
tmp_fifofile="/tmp/$$.fifo"#以指令碼執行的當前程式ID號作為檔名。
mkfifo "$tmp_fifofile"#新建一個隨機FIFO管道檔案。
exec 5<>"$tmp_fifofile"#定義檔案描述符5指向這個FIFO管道檔案(對檔案描述符5的所有操作等同於對管道檔案)。
rm $tmp_fifofile#刪除管道檔案,刪除與否都無所謂。
for ((i=0;i<$THREAD_NUM;i++));do echo done >&5#使用一個for迴圈向管道中輸入$THREAD_NUM個空行;>符號為輸出重定向;&符號表示5為檔案描述符,也就是說&5表示檔案描述符5。
read -u5#表示從檔案描述符5(管道)中讀取行,每次讀一行,如果讀完了就會掛起,直到管道中再次有可讀的行。
echo >&5#再次向管道中寫入空行,避免掛起的for迴圈停止執行。
} &#將程式放到後臺,表明for迴圈中的sleep 1----------這兩條指令有10個程式在後臺同時執行
wait等待所有程式執行完成
exec 5>&-#刪除檔案描述符5

關聯詳解

Linux檔案描述符

  檔案描述符在形式上是一個非負整數。實際上,它是一個索引值,指向核心為每一個程式所維護的該程式開啟檔案的記錄表。當程式開啟一個現有檔案或者建立一個新檔案時,核心向程式返回一個檔案描述符。在程式設計中,一些涉及底層的程式編寫往往會圍繞著檔案描述符展開。但是檔案描述符這一概念往往只適用於UNIX、Linux這樣的作業系統。
  每個Unix程式(除了可能的守護程式)應均有三個標準的POSIX檔案描述符,對應於三個標準流:
| 整數值 | 名稱 | <unistd.h>符號常量 | <stdio.h>檔案流 |
|----|----|----|----|
|0|Standard input|STDIN_FILENO|stdin
|1|Standard output|STDOUT_FILENO|stdout
|2|Standard error|STDERR_FILENO|stderr
  我們可以使用exec指令自行定義、繫結檔案描述符,檔案描述符一般從3~(n-1)可以使用,n=ulimit -n的數值。

管道

  Linux管道包含兩種

  • 匿名管道
  • 命名管道

  管道有一個特點,如果管道中沒有資料,那麼取管道資料的操作就會滯留,直到管道內進入資料,然後讀出後才會終止這一操作;同理,寫入管道的操作如果沒有讀取管道的操作,這一動作就會滯留。

匿名管道

  在Unix或類Unix作業系統的命令列中,匿名管道使用ASCII中垂直線|作為匿名管道符,匿名管道的兩端是兩個普通的,匿名的,開啟的檔案描述符:一個只讀端和一個只寫端,這就讓其它程式無法連線到該匿名管道。

命名管道

  命名管道也稱FIFO,從語義上來講,FIFO其實與匿名管道類似,但值得注意:

  • 在檔案系統中,FIFO擁有名稱,並且是以裝置特俗檔案的形式存在的;
  • 任何程式都可以通過FIFO共享資料;
  • 除非FIFO兩端同時有讀與寫的程式,否則FIFO的資料流通將會阻塞;
  • 匿名管道是由shell自動建立的,存在於核心中;而FIFO則是由程式建立的(比如mkfifo命令),存在於檔案系統中。

相關文章