shell“多线程”实现方法

一、预备知识

1. 文件描述符File Descriptor

    Linux shell中的File Descriptor可以理解为一个指向文件的指针。默认有三个FD:0,1,2。分别指向的是:Keyboard设备文件,Moniter设备文件,和Moniter设备文件。

Shell中还允许有3..9的FD,默认都没有打开,可以认为指向的为null。

可以通过一下命令查看得开的FD:
ls /proc/self/fd
返回的数字代表FD的值。

利用重定向可以为一个FD赋值,使其指向一个非null的文件,其实就是打开一个FD。
6>&1
可以理解为将FD6指针指向FD1指针指向的文件,既Moniter。这样,FD6和FD1就同时指向同一个文件:Moniter。

6>&-
可以理解为将FD6指针置为空值null,即关闭FD6。

一个重定向只在当前命令中有效。通过exec可以使IO重定向在当前shell中长期有效。
exec 6>&1
# 关闭FD6。

exec 6>&-

2. 命名管道FIFO

    "FIFO"是一种特殊的文件类型,它允许独立的进程通讯。 一个进程打开FIFO文件进行写操作,而另一个进程对之进行读操作, 然后数据便可以如同在shell或者其它地方常见的的匿名管道一样流线执行。mkfifo命令可以创建一个fifo

二、shell实现多线程

    通过事先向一个fifo中写一些字符,一个进程开始前先从fifo中读走一个字符,执行完之后再写会一个字符,如果没有字符的话,该线程就会等待,fifo就成了一个锁。用到的代码如下

function set_fifo_fd6() {
    local tmp_fifofile="/tmp/$$.fifo"
    mkfifo "$tmp_fifofile"
    exec 6<>"$tmp_fifofile"
    rm $tmp_fifofile
    return 0
}

function unset_fifo_fd6() {
    exec 6>&-
    return 0
}

function sub_thread_begin() {
    read -u6
    return 0
}

function sub_thread_end() {
    echo >&6
    return 0
}

function init_thread_num_fd6() {
    local thread_num=$1
    local i
    for ((i=0;i<$thread_num;i++));do
        echo
    done >&6
    return 0
}

下面是一个例子,输出的时候可以发现基本是三个三个一组,原因是第四个启动的线程已经读不到字符,被阻塞。

#! /bin/bash

#source 上面的代码
. /home/webadmin/shell/multithread.sh
set_fifo_fd6
init_thread_num_fd6 3
for (( i=0; i < 10; i++ ))
do
    {
        sub_thread_begin
        sleep 2
        echo "thread $i"
        sub_thread_end
    }&
done
#要有wait,等待所有线程结束
wait
unset_fifo_fd6


留言: