shell多线程

微笑、不失礼 提交于 2020-08-05 11:20:41

最近看到一个前辈留下的shell,发现竟然是shell多线程,便研究了下。也许你会有疑问,Shell这么简单的脚本语言有多线程这一说吗?答案是有的。只不过它实现起来稍微有点难理解罢了,因为它借助了命名管道实现。所谓多线程就是原本由一个进程完成的事情现在由多个线程去完成。假如一个进程需要10小时完成的事情,现在分配10个线程,给他们分工,然后同时去做这件事情,最终可能就需要1小时。

文件描述符:
文件描述符(缩写fd)在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。每一个unix进程,都会拥有三个标准的文件描述符,来对应三种不同的流:
shell多线程
除了上面三个标准的描述符外,我们还可以在进程中去自定义其他的数字作为文件描述符。每一个文件描述符会对应一个打开文件,同时,不同的文件描述符也可以对应同一个打开文件;同一个文件可以被不同的进程打开,也可以被同一个进程多次打开。


命名管道
我们前面在shell脚本中多次用过这个管道符号'|',这个叫做匿名管道,也就是说它并没有名字,而这里提到的管道叫做命名管道,功能和那个匿名管道基本上是一样的。命名管道,英文名First In First Out,简称FIFO。命名管道有如下特点:1)在文件系统中,FIFO拥有名称,并且是以设备特殊文件的形式存在的;
2)任何进程都可以通过FIFO共享数据;
3)除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;
4)匿名管道是由shell自动创建的,存在于内核中,而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中;
5)匿名管道是单向的字节流,而FIFO则是双向的字节流;
我们可以把命名管道和文件描述符结合起来:
mkfifo test.fifo
exec 100<>test.fifo //这样可以把fd100的读和写全部指定到test.fifo中
ls -l /dev/fd/100 //可以看到fd100已经指向到了/root/test.fifo








read命令
在shell脚本中,read命令使用还是比较多的,最典型的用法是,和用户交互。

read的-u选项后面可以跟fd,如下:
read -u10 a //这样会把fd10里面的字符串赋值给a
注意,这里的fd10就是前面我们定义的test.fifo,如果你的fd10里还没有任何的内容写入,那么你执行上面这条命令会卡着不动。因为fd10是一个命名管道文件,只有写入了东西,read才会读到,否则就一直卡着,等待写入内容。当然,这个命名管道文件可以写入多行,先储存起来,然后等着read去读。

wait命令
ait命令顾名思义就是等待的意思,即等待那些在没有完成的任务(主要是后台的任务),直到所有任务完成后,才会继续执行wait以后的指令,常用于shell脚本中。以下是关于wait指令的示例:
sleep 5 &
wait


结合命名管道和read实现多线程
命名管道有两个很明显的特点:
1)先进先出,比如上例中我们给fd10写入了两行内容,则第一次read第一行,第二次read第二行。
2)有内容read则执行,没有则阻塞,例如上例中,read完两次后,如果你再执行一次read,则它就会一直卡着,直到我们再次写入新的内容它才会read到。
利用这两个特点,我们就可以实现shell的多线程了:
#创建命名管道123.fifo文件
mkfifo 123.fifo
#将命名管道123.fifo和文件描述符1000绑定,即fd1000的输入输出都是在123.fifo中
exec 1000<>123.fifo







#连续向fd1000中写入两次空行
echo >&1000
echo >&1000

#循环10次
for i in seq 1 10
do
#每循环一次,读一次fd1000中的内容,即空行,只有读到空行了,才会执行{ }内的指令
#每次循环都需要打印当前的时间,休眠1秒,然后再次向fd1000中写入空行,这样后续的read就有内容了
#read指令不仅可以赋值,也可以跟一个函数,用{ }括起来,函数中是多条指令
read -u1000
{
date +%T
echo $i
sleep 1
echo >&1000
} &; //丢到后台去,这样10次很快就循环完,只不过这些任务是在后台跑着。由于我们一开始就向fd1000里写入了两个空行,所以read会一次性读到两行。
done
#等待所有后台任务执行完成
wait
#删除fd1000
exec 1000>&-
#删除命名管道
rm -f 123.fifo


















执行脚本结果如下:
19:00:04
1
19:00:04
2
19:00:05
3
19:00:05
4
19:00:06
5
19:00:06
6
19:00:07
7
19:00:07
8
19:00:08
9
19:00:08
10



















标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!