PHP 文件锁与进程锁的使用示例


Posted in PHP onAugust 07, 2017

鉴于前面介绍了swoole,就借用swoole的服务器/客户端与多进程机制对锁进行说明.

这里只针对PHP的锁机制进行说明,由于SQL的锁与其作用方式和应用场景不同,将作另行说明.

1.文件锁

  • flock()
  • fclose()
  • swoole_lock()

文件锁的可能应用场景为:

1.限制并发多进程或多台服务器需要对同一文件进行访问和修改;

2.对参与文件I/O的进程队列化和人为阻塞;

3.在业务逻辑中对文件内容进行守护;

下面是文件锁C/S通讯机制下的使用,已经省略了具体的通讯过程

Server(服务器通讯过程已略):

//监听数据发送事件
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
  $serv->send($fd, "ServerEnd");

  $p_file = "locktest.txt";
  var_dump(file_get_contents($p_file));
});

Client1(服务器通讯过程已略):

$s_recv = "ww";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加锁方式:
flock($o_file,LOCK_EX);

// // swoole加锁方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();

fwrite($o_file, 'ss' . $s_recv);

sleep(30);
// 两种解锁方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

Client2(服务器通讯过程已略):

$s_recv = "xx";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加锁方式:
flock($o_file,LOCK_EX);

// // swoole加锁方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();


fwrite($o_file, 'ss' . $s_recv);

// 两种解锁方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

结果:

Client2被阻塞了30s,直到Client1执行结束才对文件进行了一次写入;

[l0.16@4 m29.5% c30s04] $ php swoole_client2.php

需要注意的是:

1.无论是flock()还是swoole提供的swoole_lock(),都有在进程结束时自动解锁的机制,所以在demo中即使不进行手动解锁也能正常运行,因此这里在第一个Client中执行了sleep()暂停函数来观察文件锁的效果;

2.flock()的标准释放方式为flock($file,LOCK_UN);, 但是个人喜欢fclose(),永绝后患;

2.进程锁

与文件锁不同的是,进程锁并不用于阻止对文件的I/O,而是用于防止多进程并发造成的预期之外的后果.所以需要在多进程并发时将其队列化,即在某进程的关键逻辑执行结束前阻塞其他并发进程的逻辑执行.

实现思路有几种:

1.利用flock()文件锁,创建一个临时lock文件,使用LOCK_NB模拟阻塞或非阻塞流,再在进程内部使用判定条件控制逻辑执行;

非阻塞模型demo:

$p_file = "locktest.txt";
$o_file = fopen($p_file, 'w+');

// 如果临时文件被锁定,这里的flock()将返回false
if (!flock($o_file, LOCK_EX + LOCK_NB)) {
  var_dump('Process Locked');
}
else {
  // 非阻塞模型必须在flock()中增加LOCK_NB参数
  // 当然,这里取消LOCK_NB参数就是阻塞模型了
  flock($o_file, LOCK_EX + LOCK_NB);
  var_dump('Process Locking');
  // 模拟长时间的执行操作
  sleep(10);
}

2.利用swoole提供的共享内存,缓存方法或通信方法在不同的进程中传递一个全局变量,进程获取该变量的状态后使用判定条件控制逻辑执行;

传递变量的方法很多,这里只提供一个思路,就以memcached为例;

阻塞模型demo:

// 初始化memcached
$memcached = new Memcache;
$memcached->connect("localhost", 11211);

// 获取用来做状态判定的全局变量
$s_flag = $memcached->get("flag");

if (!$s_flag) {
  // 这里利用了memcached的过期时间作为演示,实际上业务处理完成后销毁该变量即可
  $memcached->set("flag", "locked", 0, 10);
  main();
}
else {
  // 阻塞模型
  while ($s_flag == 'locked') {
    var_dump('Process locked, retrying...');
    // 设置重试时间, 避免过于频繁的操作尝试
    sleep(1);
    // 更新状态变量
    $s_flag = $memcached->get("flag");
  }
  // // 非阻塞模型
  // if ($s_flag == 'locked') {
  //   var_dump('Process locked, suspended');
  //   die();
  // }
  main();
}

// 模拟业务主函数
function main() {
  var_dump('Process Running');
  // 业务执行结束后回收memcached
  // $memcached->delete("flag");
}

这里需要注意的是:

1.memcached的过期时间不可少于程序运行的实际时间,因此建议稍微长一点,逻辑执行结束后进行回收;

2.在非阻塞模型中,若状态被判定为false,应该将进程中止或block,避免业务逻辑的继续执行;

3.在实际应用中,设置一个重试时间很有必要,这样可以很大程度上减少针对memcached的大量I/O并发,减轻服务器压力;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php上传、管理照片示例
Oct 09 PHP
mysq GBKl乱码
Nov 28 PHP
PHP中header和session_start前不能有输出原因分析
Jan 11 PHP
CodeIgniter图像处理类的深入解析
Jun 17 PHP
解析Win7 XAMPP apache无法启动的问题
Jun 26 PHP
php生成txt文件标题及内容的方法
Jan 16 PHP
采用header定义为文件然后readfile下载(隐藏下载地址)
Jan 31 PHP
详解WordPress开发中过滤属性以及Sql语句的函数使用
Dec 25 PHP
PHP模糊查询的实现方法(推荐)
Sep 06 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
OAuth认证协议中的HMACSHA1加密算法(实例)
Oct 25 PHP
详解PHP 7.4 中数组延展操作符语法知识点
Jul 19 PHP
PHP实现找出有序数组中绝对值最小的数算法分析
Aug 07 #PHP
php基于session锁防止阻塞请求的方法分析
Aug 07 #PHP
在Yii2特定页面如何禁用调试工具栏Debug Toolbar详解
Aug 07 #PHP
PHP编程中的Session阻塞问题与解决方法分析
Aug 07 #PHP
PHP基于IMAP收取邮件的方法示例
Aug 07 #PHP
PHP与JavaScript针对Cookie的读写、交互操作方法详解
Aug 07 #PHP
php+javascript实现的动态显示服务器运行程序进度条功能示例
Aug 07 #PHP
You might like
两种设置php载入页面时编码的方法
2014/07/29 PHP
getJSON跨域SyntaxError问题分析
2014/08/07 PHP
php解析json数据实例
2014/08/19 PHP
php获取指定范围内最接近数的方法
2015/06/02 PHP
php实现XML和数组的相互转化功能示例
2017/02/08 PHP
jQuery之过滤元素操作小结
2013/11/30 Javascript
js使用html()或text()方法获取设置p标签的显示的值
2014/08/01 Javascript
JavaScript中获取高度和宽度函数总结
2014/10/08 Javascript
浅谈jQuery中 wrap() wrapAll() 与 wrapInner()的差异
2014/11/12 Javascript
JavaScript中的this关键字使用方法总结
2015/03/13 Javascript
javascript+ajax实现产品页面加载信息
2015/07/09 Javascript
jQuery使用animate创建动画用法实例
2015/08/07 Javascript
详谈javascript异步编程
2016/02/21 Javascript
微信小程序 wxapp地图 map详解
2016/10/31 Javascript
原生javascript实现读写CSS样式的方法详解
2017/02/20 Javascript
详解Vue爬坑之vuex初识
2017/06/14 Javascript
mui框架移动开发初体验详解
2017/10/11 Javascript
打字效果动画的4种实现方法(超简单)
2017/10/18 Javascript
angular1.x ui-route传参的三种写法小结
2018/08/31 Javascript
nodeJs项目在阿里云的简单部署
2020/11/27 NodeJs
[01:10]DOTA2亚洲邀请赛 征战号角响彻全场
2015/01/06 DOTA
用Python编程实现语音控制电脑
2014/04/01 Python
从零学python系列之教你如何根据图片生成字符画
2014/05/23 Python
非递归的输出1-N的全排列实例(推荐)
2017/04/11 Python
Python基础知识_浅谈用户交互
2017/05/31 Python
Python 装饰器使用详解
2017/07/29 Python
python3 遍历删除特定后缀名文件的方法
2018/04/23 Python
详解Python连接MySQL数据库的多种方式
2019/04/16 Python
使用 Python 快速实现 HTTP 和 FTP 服务器的方法
2019/07/22 Python
matplotlib部件之套索Lasso的使用
2021/02/24 Python
Baracuta官方网站:Harrington夹克,G9,G4,G10等
2018/03/06 全球购物
外包公司软件测试工程师
2014/11/01 面试题
出生医学证明样本
2014/01/17 职场文书
爱国卫生月活动总结范文
2014/04/25 职场文书
教师职位说明书
2014/07/29 职场文书
运动会闭幕词
2015/01/28 职场文书