一个游戏肯定是多个进程(线程)进行的, 例如我们在控制自己的坦克的同时, 敌方坦克肯定需要自主随机的移动,这就需要将其放到后台中。
将一个进程放到后台很简单,执行脚本时,只需在指令末尾加 & 符号即可。
[root@NCTEST ~]# ping baidu.com > /dev/null & [1] 16313 [root@NCTEST ~]# ping baidu.com > /dev/null & [2] 16316 [root@NCTEST ~]# ps aux | grep ping root 16313 0.0 0.0 109576 1032 pts/2 S 13:28 0:00 ping baidu.com # 可以看到有两个运行在后台的ping进程 root 16316 0.0 0.0 109576 1020 pts/2 S 13:28 0:00 ping baidu.com root 16320 0.0 0.0 103252 848 pts/2 R+ 13:28 0:00 grep ping [root@NCTEST ~]# [root@NCTEST ~]# jobs #查看当前进程下的运行在后台的子进程 [1]- Running ping baidu.com > /dev/null & [2]+ Running ping baidu.com > /dev/null & [root@NCTEST ~]# kill %1 #结束后台子进程的方式 [root@NCTEST ~]# kill %2 [1]- Terminated ping baidu.com > /dev/null [2]+ Terminated ping baidu.com > /dev/null [root@NCTEST ~]# jobs [root@NCTEST ~]#
对于此游戏而言,关于后台运行的知识点以上足以, 更多相关的内容请参考链接:https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/
(或参考收录:http://www.cnblogs.com/gipagod/p/9121255.html)
一个进程放入后台后, 我们是无法直接控制的, 例如敌方坦克被击中后,如何通知其终止移动,并显示爆炸图案? 这就需要信号的发送和接收了,简单点说,放到后台的进程会一直在监听某个信号,一旦有信号发送过来就会执行制定好的动作,这样就方便被前台进程控制了。
一般现在的Linux中都会有64种信号,如下, 但前32中一般都已由默认动作,例如我们通常用的CTRL+C组合键终止进程时其实发送的是SIGINT(2)信号等,因此不建议自定义使用,只有在我们需要对已存在信号动作进行修改时才会用到,例如忽略CTRL+C操作等等。
[root@NCTEST ~]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
下面介绍一下它的使用,首先是接受方, 接收方使用trap指令来监听信号,语法如下:
trap 'commands' signal-list # 监听到信号后执行commands trap '' signal-list # 忽略信号,不执行任何操作,主要用来屏蔽某些已有默认动作的信号,例如SIGINT等 trap signal-list # 采取信号默认动作(用处不大)
对于发送发,我们使用kill指令来实现:
kill -signal ProcessID
kill的参数中需要一个ProcessID,也就是我们放到后台运行进程的ID,这个ID我们可以通过变量 $! 来获取, 它的作用是存储最近一次放到后台运行的进程的ID:
[root@GipagodHost ~]# ping gipagod.com >/dev/null & [1] 7903 [root@GipagodHost ~]# echo $! 7903 [root@GipagodHost ~]# ping gipagod.com >/dev/null & [2] 7904 [root@GipagodHost ~]# echo $! 7904 [root@GipagodHost ~]# ps aux | grep ping root 7903 0.0 0.1 111636 1036 pts/1 S 14:34 0:00 ping gipagod.com root 7904 0.0 0.1 111636 1032 pts/1 S 14:34 0:00 ping gipagod.com root 7906 0.0 0.0 105368 884 pts/1 S+ 14:34 0:00 grep ping
我们需要在每次后台运行一个进程后,立刻用一个变量存储器, 用一段测试代码来加深以上两个知识点的理解:
f_print_signal(){ echo "I have received the signal, number is $1" } f_bg_func(){ local v_stop=0 # 定义个局部变量 trap "f_print_signal 40" 40 # 监听了三个信号 trap "f_print_signal 50" 50 trap "f_print_signal 45; v_stop=1" 45 # 打印信号数字的同时将v_stop置1,终止下面的while循环,即此结束了此后台进程的运行 while [[ $v_stop -eq 0 ]] # 当接收到45信号后,v_stop被置1, 不在符合循环条件,终止循环 do sleep 1 done echo GOODBYE } f_bg_func & v_bg_pid=$! # 存储后台进程的Process ID while : do read v_input kill -$v_input $v_bg_pid # 向后台进程发送信号 done
展示:
[root@GipagodHost ~]# sh Tank6_1.sh 40 I have received the signal, number is 40 50 I have received the signal, number is 50 50 I have received the signal, number is 50 40 I have received the signal, number is 40 45 I have received the signal, number is 45 GOODBYE 40 Tank6_1.sh: line 25: kill: (14171) - No such process # 45信号已经终止了后台进程的运行