linux 单例进程,[实践] 单例进程模式

有时候,我们需要限制某个程序只启动单一实例进程以实现单例模式(如守护进程)。那么,在UNIX/Linux环境下,有多少种方法可以实现这一需求?它们的可靠性如何?下面是一些总结心得。

[方法一:使用ps命令对当前同名进程计数]

互斥执行最可靠的办法是使用互斥锁。但是跨进程使用互斥锁是个相当麻烦的事情,再者,某些古旧的UNIX上并没有此类锁。于是最土的解决方法是使用ps命令列出当前同名命令行条目并计数,如果数值大于1,则表示程序已经启动过一次,当前进程可以安心退出。

以经典Shell编程为例,最常见的对同名命令行条目计数的写法是:

count=`ps -ef | grep xxxx.sh | grep -v grep | wc -l`

首先使用ps -ef列出所有进程,然后grep出同名命令行条目(即含有“xxxx.sh”字符串的条目,默认按行分隔),同时排除掉grep命令自己的条目,最后使用wc -l完成计数。相当直白的代码,一目了然,对不对?很可惜,这个写法有非常隐晦的Bug。

Shell通过调用fork()来生成子进程,并在子进程中调用exec()来替换执行具体命令(如ps和grep命令,进程号不变),从而建立起完整的管道线。Bug产生自a) fork()出的子进程在调用exec()之前,ps命令列出的子进程命令行条目与父进程命令行条目相同,同时b) fork()和exec()不是在一次原子调用中完成的。在fork()之后、exec()之前,操作系统刚好调度ps进程执行的话,那么得到的结果很可能包含2~4个含有“xxxx.sh”字符串的条目,这将导致count值不准确,最终执行与预期不相符的后续代码。

在这里,分析Bug的要点是,管道线的各个组成命令不是串行建立和执行的,当执行结果依赖于特定的执行顺序时,并发或并行执行会产生微妙的竞态条件。避免方法也很简单,只要打破这一依赖即可:

list=`ps -ef`

count=`echo "${list}" | grep xxxx.sh | grep -v grep | wc -l`

在上述代码中,ps -ef执行时fork()和exec()早已完成,不存在因子进程未替换执行具体命令所带来的同名条目,若有,则可以肯定是在其它终端以相同命令行启动了同一Shell程序所致,从而避免了计数不准确的问题。

(未完待续……)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值