并发锁(二):共享锁和独占锁

简介: 并发锁(二):共享锁和独占锁

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

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

在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次该代码,正常上锁并正常读取数据:

image.png

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

<?php
$file = fopen('1.txt','r');
if (flock($file,LOCK_EX)){
    $data = fread($file,1);
    var_dump($data);
    echo "加锁成功";
    fread(STDIN,1);
}

image.png

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

image.png

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

注意事项

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

例如:

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

<?php
$file = fopen('1.txt','r+');
fwrite($file,2,1);

数据将会出现变动:

image.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将会阻塞,无法加锁:

image.png

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

注意事项

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

<?php
$file = fopen('1.txt','r+');
$result = fwrite($file,'65555555');
var_dump($result);
var_dump(fread($file,11));

image.png

其他

非阻塞

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

<?php
$file = fopen('1.txt','r+');
if (flock($file,LOCK\_EX|LOCK\_NB)){
    echo "加锁成功\\n";
}else{
    echo "加锁失败";
}

image.png

并发解决

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

目录
相关文章
|
7月前
|
存储 监控
多线程之AQS独占锁
多线程之AQS独占锁
59 0
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
92 1
|
4月前
|
SQL 关系型数据库 MySQL
MySQL使用行级锁时,并非直接锁定记录,而是锁定涉及的索引。对于表`user_item`,更新语句先锁定非主键索引`idx_1`,再锁定主键索引。若两条更新语句分别按不同顺序锁定这两个索引,可能导致互相等待对方释放锁,引发死锁。解决方案包括先查询待更新记录的主键,再按主键更新,确保一致的锁定顺序。
44 2
|
7月前
|
存储 安全 Java
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
85 1
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
|
Linux API C++
锁、避免死锁等相关
锁、避免死锁等相关
69 0
《锁》有那些?
锁是计算机科学中用于控制对共享资源的访问的一种同步机制。不同种类的锁适用于不同的场景和需求。下面是一些常见的锁的种类及其详细介绍:
82 1
|
存储 算法 安全
辛辛苦苦的劳动成果,如何上把锁?
辛辛苦苦的劳动成果,如何上把锁?
|
安全 Java 调度
认识并发中常见的锁
1. 锁的作用 2. 乐观锁和悲观锁 1)乐观锁 2)悲观锁 3)乐观锁和悲观锁在 Java 中的典型实现 4)数据版本机制 3. CAS 机制 1)什么是 CAS 2)CAS 的 ABA 问题 4. 读写锁 1)Java 标准库中提供的读写锁 5. 偏向锁、轻量级锁和重量级锁 1)偏向锁 2)轻量级锁 3)重量级锁 6. 自旋锁 7. 公平锁和非公平锁
119 0
|
Java
各种锁的理解
各种锁的理解
119 0
各种锁的理解
|
生物认证
什么是锁?
什么是锁?
138 0
什么是锁?