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面向对象编程快速入门
Dec 14 PHP
在普通HTTP上安全地传输密码
Jul 21 PHP
PHP删除数组中的特定元素的代码
Jun 28 PHP
PHP mail()函数使用及配置方法
Jan 14 PHP
Yii2使用小技巧之通过 Composer 添加 FontAwesome 字体资源
Jun 22 PHP
两个php日期控制类实例
Dec 09 PHP
腾讯微博提示missing parameter errorcode 102 错误的解决方法
Dec 22 PHP
Symfony数据校验方法实例分析
Jan 26 PHP
php中的常用魔术方法汇总
Feb 14 PHP
PHP实现动态执行代码的方法
Mar 25 PHP
PHPExcel简单读取excel文件示例
May 26 PHP
PHP读取Excel类文件
May 15 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
IIS6.0 开启Gzip方法及PHP Gzip函数分享
2014/06/08 PHP
基于php实现的验证码小程序
2016/12/13 PHP
农历与西历对照
2006/09/06 Javascript
javascript 实现父窗口引用弹出窗口的值的脚本
2007/08/07 Javascript
Jquery 扩展方法
2010/05/06 Javascript
node.js中的fs.utimes方法使用说明
2014/12/15 Javascript
详解JavaScript中的forEach()方法的使用
2015/06/08 Javascript
微信小程序开发之入门实例教程篇
2017/03/07 Javascript
jQuery使用eraser.js插件实现擦除、刮刮卡效果的方法【附eraser.js下载】
2017/04/28 jQuery
浅谈Angular路由守卫
2017/08/26 Javascript
基于vue 实现token验证的实例代码
2017/12/14 Javascript
微信小程序自定义组件封装及父子间组件传值的方法
2018/08/28 Javascript
Vue常见面试题整理【值得收藏】
2018/09/20 Javascript
nodejs微信开发之接入指南
2019/03/17 NodeJs
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
JavaScript基础之this和箭头函数详析
2019/09/05 Javascript
vue.js实现左边导航切换右边内容
2019/10/21 Javascript
解决Vue打包上线之后部分CSS不生效的问题
2019/11/12 Javascript
js实现简单点赞操作
2020/03/17 Javascript
Vue——解决报错 Computed property "****" was assigned to but it has no setter.
2020/12/19 Vue.js
python绘制简单彩虹图
2018/11/19 Python
Python常用的json标准库
2019/02/19 Python
详解Python3 pandas.merge用法
2019/09/05 Python
Python如何读取文件中图片格式
2020/01/13 Python
python异常处理try except过程解析
2020/02/03 Python
TensorFlow:将ckpt文件固化成pb文件教程
2020/02/11 Python
如何基于Python代码实现高精度免费OCR工具
2020/06/18 Python
python搜索算法原理及实例讲解
2020/11/18 Python
html5 Canvas画图教程(11)—使用lineTo/arc/bezierCurveTo画椭圆形
2013/01/09 HTML / CSS
综合内勤岗位职责
2014/04/14 职场文书
个人求职信范文
2014/05/24 职场文书
陕西导游词
2015/02/04 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
2016年会开场白台词
2015/06/01 职场文书
Android开发之WECHAT微信小程序路由跳转的两种形式
2022/04/12 Java/Android
错误码NET::ERR_CERT_DATE_INVALID证书已过期解决方法?
2022/07/07 数码科技