如@felix021 所说,flock($res, LOCK_EX|LOCK_NB) 是有效的,请好好看文档……
@卖掉内裤去上网 所说,memcached 虽然是纯内存操作,但毕竟有网络或unix domain socket开销,为了一个文件锁去启动一个Memcached未免太浪费。Linux中可以使用共享内存来做锁,请参考php手册中 shm_has_var / shm_put_var 。
如你自己说的,每进程分配一个专有文件也是可以的,并不是很麻烦,如果所有工作进程都有一个主进程fork出来就更方便了,最简单最dirty的办法是,把文件名放在主进程数组里,每次fork之前,就pop出来一个文件名……
用文件rename的方法跟@卖掉内裤去上网 说的依靠判断一个lock文件存在与否的办法开销差不多,如果你的文件数不是很多,锁抢占不频繁,可以这么做……
除了文件锁以外,其他自行实现的锁在有锁进程意外退出时,都需要自行实现解锁机制。所以,还是推荐用文件锁,会由系统来自动释放……
关于flock的演示function do_flock(){
ob_implicit_flush(true); //关闭PHP输出缓冲
$file = __FILE__;
$f = fopen($file, 'r');
$count = 0;
while(1){
$locked = flock($f, LOCK_NB | LOCK_EX);
if($locked) {
echo "GOT LOCK\n";
sleep(10);
flock($f, LOCK_UN);
echo "RELEASE LOCK\n";
break;
} else {
echo 'LOCKED BY OTHER, WAIT:' . ($count ++) . "\n";
sleep(1);
}
}
}
测试方法:time curl --no-buffer "http://localhost/flock"
//在10秒钟之内另外一个terminal里再执行相同命令
Terminal 1 输出:GOT LOCK
RELEASE LOCK
real0m10.023s
user0m0.008s
sys0m0.008s
Terminal 2 输出:LOCKED BY OTHER, WAIT:0
LOCKED BY OTHER, WAIT:1
LOCKED BY OTHER, WAIT:2
LOCKED BY OTHER, WAIT:3
LOCKED BY OTHER, WAIT:4
LOCKED BY OTHER, WAIT:5
LOCKED BY OTHER, WAIT:6
LOCKED BY OTHER, WAIT:7
LOCKED BY OTHER, WAIT:8
GOT LOCK
RELEASE LOCK
real0m19.025s
user0m0.008s
sys0m0.008s
Ubuntu 12.04 测试通过,没有Mac没法测,但应该没啥问题,毕竟是同根同源的,PHP源码里也只是对Win有特殊实现……
注意,以下情况会影响输出效果浏览器有渲染缓冲,webkit核心的浏览器大概需要额外输出4k字节的空白才会开始渲染输出
如果用FastCGI方式部署的PHP,Web服务器可能会有输出缓冲,我用的Cherokee大概也是4k左右的缓冲
针对这些缓冲,可以在每次echo时,把内容用str_pad补齐4096字节