php独占登录,并发锁(二):共享锁和独占锁

在上篇的文章中,我们了解了为什么需要锁,以及锁的应用场景。

那么,该怎么用锁来进行并发业务逻辑呢?

在php中,已经提供了关于锁的函数 flock

flock(file,lock,block)

参数描述

file必需。规定要锁定或释放的已打开的文件。

lock必需。规定要使用哪种锁定类型。

可能的值:LOCK_SH - 共享锁定(读取的程序)。允许其他进程访问该文件。

LOCK_EX - 独占锁定(写入的程序)。防止其他进程访问该文件。

LOCK_UN - 释放一个共享锁定或独占锁定

LOCK_NB - 锁定的情况下避免阻塞其他进程。

block可选。若设置为 1,则当进行锁定时阻塞其他进程。

首先,我们要分清楚,锁有2种,共享锁,以及独占锁

共享锁

共享锁用于某个文件不会被写,或者不会被更新(也就是只读)的情况,加了共享锁的文件,只能再加共享锁,而不能加独占锁

例如:$file = fopen('1.txt','r');

if (flock($file,LOCK_SH)){

//读取一次文件的数据

$data = fread($file,1);

var_dump($data);

echo "加锁成功\n";

//阻塞一次,方便运行另一个测试文件

fread(STDIN,1);

//文件指针重置

fseek($file,0);

//继续获取

$data = fread($file,1);

var_dump($data);

}

运行2次该代码,正常上锁并正常读取数据:

c5684295b4f6a99eb7bbd9d035fdb725.png

同样,如果在上了共享锁的情况,增加独占锁,则该进程会阻塞,直到共享锁释放:<?php

$file = fopen('1.txt','r');

if (flock($file,LOCK_EX)){

$data = fread($file,1);

var_dump($data);

echo "加锁成功";

fread(STDIN,1);

}

39365167d18275b5d101797ec61c00b8.png

需要所有的共享锁文件释放,才可加锁成功:

803568733973f08f1f0feee3da4f92e3.png

同理,如果是先加了独占锁,则共享锁会被阻塞,不做详细说明

注意事项

共享锁加上之后,虽然不能再加上独占锁进行独占写入,但是还是会被未加锁的进程影响,所以注意,当你确定某个文件是只读,或者说读取的时候不被写入影响时,关于操作这个文件的代码,都需要增加锁,不管是独占锁还是共享锁,否则数据还是会出现问题

例如:

当加好共享锁之后,运行这段代码:<?php

$file = fopen('1.txt','r+');

fwrite($file,2,1);

数据将会出现变动:

02606b197260048a0323e6da2a06118e.png

独占锁

独占锁用于数据可能会被修改的文件,当一个进程加上独占锁之后,其他进程将不能增加独占锁和共享锁(将会阻塞)

测试代码:<?php

$file = fopen('1.txt','r+');

if (flock($file,LOCK_EX)){

echo "加锁成功\n";

//读取一次文件的数据

$data = fread($file,11);

var_dump($data);

//读取一次文件的数据

$time = time();

//文件指针重置

fseek($file,0,SEEK_SET );

$data = fwrite($file,$time,strlen($time));

//阻塞一次,方便运行另一个测试文件

fread(STDIN,11);

//文件指针重置

fseek($file,0,SEEK_SET );

//继续获取

$data = fread($file,11);

var_dump($data);

}

当进程1运行该代码时,进程2将会阻塞,无法加锁:

dcf72bf9e85c9a6be090c968346dcb64.png

同样,共享锁也会出现一样的情况(不做测试)

注意事项

独占锁加上之后,虽然其他进程无法加共享锁以及独占锁,但是可以直接写入文件,同样会造成数据污染,所以注意,当你确定某个文件确定需要加锁时,关于操作这个文件的代码,都需要增加锁,不管是独占锁还是共享锁,否则数据还是会出现问题<?php

$file = fopen('1.txt','r+');

$result = fwrite($file,'65555555');

var_dump($result);

var_dump(fread($file,11));

bd85e6ebe08e188644fd13392ab44fc0.png

其他

非阻塞

通过在flock函数中的参数中增加LOCK_NB,可以避免阻塞,当不能加锁时会直接返回失败:<?php

$file = fopen('1.txt','r+');

if (flock($file,LOCK_EX|LOCK_NB)){

echo "加锁成功\n";

}else{

echo "加锁失败";

}

3e20b57c4da45841bf0986d93233258f.png

并发解决

还记得第一篇并发锁的文章吗?通过这个方式,就可以实现同一个文件在同一时间自有一个进程访问了

并发锁系列文章

本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值