shell并发控制
1.文件描述符
File Descriptors (FD,文件描述符或文件句柄):进程使用文件描述符来管理打开的文件
查看当前进程的fd
确定以下三点
如何exec打开一个文件
exec 3<> file1.txt
如何exec关闭一个文件(释放文件句柄)
如果没有释放句柄,文件删除后描述符依然还在
exec 3<&-
当一个文件FD未被释放,删除源文件也不会影响FD
rm -rf file1
cp /proc/$$/3 file1
[root@localhost my_scripts]# ll /proc/$$/fd 总用量 0 lrwx------ 1 root root 64 2月 11 11:35 0 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 11:35 1 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 11:35 2 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 14:07 255 -> /dev/pts/2 创建一个文件 touch /root/file1.txt exec 3<> /root/file1.txt 在当前进程打开这个文件,3代表文件描述符 将文件中输入内容 echo "123" >/proc/$$/fd/3 cat /root/file1.txt 这是123就会出现在file1中,因为描述符3打开了这个文件 删除/root/file1 rm -rf /root/file 这时ll /proc/$$/fd就会输出如下结果 [root@localhost my_scripts]# ll /proc/$$/fd 总用量 0 lrwx------ 1 root root 64 2月 11 11:35 0 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 11:35 1 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 11:35 2 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 14:07 255 -> /dev/pts/2 lrwx------ 1 root root 64 2月 11 11:35 3 -> /root/file1.txt (deleted) 表示这个文件已经被删除了 根据描述符恢复删除的文件 cp /proc/$$/fd/3 /root/file1 文件恢复 但是ll /proc/$$/fd/还是会提示3已经删除,这是由于每个文件都一个特定的iload编号 关闭当前进程的文件描述符 exec 3<&-
2.再谈管道
管道分为匿名管道和命名管道
我们平时用的|叫匿名管道,其实匿名管道也是一个文件,只不过他是在我们心目中的,而命名管道是名副其实的文件,由mkfifo命令创建一个命名管道文件,命名管道文件可以跨终端输入,只显示一次。
管道文件不会被覆盖,只有当有人读到这个文件才会消失
终端1 [root@localhost my_scripts]# mkfifo /tmp/fifo1 终端2 [root@localhost ~]# grep 'sda' /tmp/fifo1 等待输入 终端1 [root@localhost my_scripts]# ll /dev/ > /tmp/fifo1 终端2 brw-rw---- 1 root disk 8, 0 2月 10 21:36 sda brw-rw---- 1 root disk 8, 1 2月 10 21:36 sda1 brw-rw---- 1 root disk 8, 2 2月 10 21:36 sda2 获得内容 再次查看则内容小时,若想再看则重新定向到文件
3.并发控制实例
脚本实现多线程并发控制的原理:
首先定义并发的数量,然后创建管道文件,并往管道文件中插入数据(可以是空行),然后定义分隔符,以分隔符xx运行管道文件,在删除管道文件,因为删除管道文件不会影响句柄,在使用read -u命令读取分隔符内容,如果能读到数据则执行对应的后台进程,如果读取不到则一直等待,并发进程并不是等所有都执行完一轮后在执行新的一轮,而是完成一个后就会返回,比如控制 的并发数是50,那么始终都会是50个后台进程一起执行,直到程序结束
3.1.ping主机实现并发控制
#!/bin/bash #----------------------控制进程并发数量--------------------- #-------------shell多进程/多线程------------------ #定义控制并发的数量 bfsl=10 #定义管道文件 fifofile=/tmp/$$.fifo #创建管道文件 mkfifo $fifofile #以文件描述符3打开管道文件 exec 3<> $fifofile #删除管道文件,因为文件描述符打开的文件即使删除句柄也不会被释放 rm -rf $fifofile #循环往管道文件中写入内容 for i in $(seq $bfsl) do echo >&3 #这个表示只写入回车 done for i in {1..254} do read -u 3 #-u表示对文件描述符进行读取,如果能读取则执行下面的命令,如果不能则等待 { ip=192.168.81.$i ping -c1 -W1 $ip &>/dev/null if [ $? -eq 0 ];then echo "$ip is up" else echo "$ip is down" fi echo >&3 #由于之前是从管道文件中读走了一行,这里要在还回去一行,让后面的进程进行使用 }& done wait exec 3>&- #释放文件描述符 echo "finish.............."
3.2.创建用户实现并发控制
#!/bin/bash #------------创建用户实现并发控制------------ #------------shell多线程/多进程------------------- #并发数量,一次性能同时存在多少个进程 bfcs=50 #管道文件 fifofile=/tmp/user_$$.fifo #创建管道文件 mkfifo $fifofile #打开管道文件并定义为分隔符4 exec 4<> $fifofile #删除管道文件 rm -rf $fifofile #向管道文件插入空行 for i in $(seq $bfcs) do echo >&4 done for i in $(seq -w 1000) do read -u 4 #读取分隔符4,如果读到行则执行下面命令,否则一直等待 { user=qwe$i useradd $user echo "123" |passwd --stdin $user &>/dev/null if [ $? -eq 0 ];then echo "$user is created..." fi echo >&4 #当运行完命令后则重新向管道文件插入新的行,以便后续进程进行使用 }& done wait exec 4>&- #当所有循环完成后释放分隔符 echo "finish........."