在开发中常常会遇到对文件的操作,对于初学者来说,往往关注的是对功能的实现,忽略了整个技术栈的连贯性质,因为WEB应用一般都是多线程和多进程的应用,所有的执行路径都可能同时会有多个客户端的请求,这就是多并发,如果程序中有对公共数据进行操作,那么在多并发中就要使用到锁的概念。
一、功能说明
LOCK_NB
选项进行控制。二、语法结构
flock ( resource $handle , int $operation [, int &$wouldblock ] ) : bool //支持版本(PHP 4, PHP 5, PHP 7)
参数 | 说明 | 使用说明 |
---|---|---|
handle | 文件系统指针,是典型地由 fopen() 创建的 resource(资源) | |
operation | 可以是以下值之一:
|
|
wouldblock | 如果锁定会堵塞的话(EWOULDBLOCK 错误码情况下),可选的第三个参数会被设置为 TRUE。(Windows 上不支持) | 经过测试Windows 上确实不支持此参数,其他平台暂未测试 |
$handle = fopen("j:/test.txt","r+"); //读写方式打开文件 if ( $handle ) { $lock = true; //windows 平台该参数无效 if( flock($handle, LOCK_SH | LOCK_NB ,$lock) ) { //使用共享锁定,其他请求可以直接进入,LOCK_NB 为不阻塞其他进程的锁定请求,建议使用 Log::write("锁定成功,开始执行", Log::EMERG); sleep(10); fclose($handle); } else { Log::write("锁定失败,开始执行", Log::EMERG); } }
$handle = fopen("j:/test.txt","r+"); if ( $handle ) { $start = time(); $isLock = false; do { sleep(1); $isLock = flock($handle,LOCK_EX | LOCK_NB ); } while ( !$isLock && (time() - $start) < 15 ); //如果请求锁定时间超过15秒则不再请求,直接处理失败 if ( $isLock ) { Log::write("锁定成功,开始执行", Log::EMERG); sleep(10); fclose($handle); } else { Log::write("锁定失败,开始执行", Log::EMERG); } }二、注意事项
mode
参数设定最好和flock的锁定标识参数operation
进行同步,如果是fopen打开文件的模式为读,则锁定的模式也必须为读;如果打开文件的模式为写,锁定的模式为读则即使使用fwrite进行数据写入,也会失败(在使用w和w+模式打开文件时会发生,使用a和a+模式就可以写入数据,可能是跟平台有关系,测试使用的是Windows),代码如下:$handle = fopen("j:/test.txt","w+"); //读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之 if ( $handle ) { $lock = true; if( flock($handle,LOCK_SH ,$lock) ) { //使用共享锁定,其他请求可以直接进入 $data = fgets($handle); Log::write("锁定成功,开始执行,读取数据为:".$data, Log::EMERG); fwrite($handle,"test"); //无法写入,而且把之前数据清空 fclose($handle); } else { Log::write("锁定失败,开始执行", Log::EMERG); } }
LOCK_SH
模式锁定文件,则不会阻塞其他客户端的操作,LOCK_EX
模式的锁定会阻塞其他客户端的操作LOCK_NB
则其他客户端会锁定失败)