文件加锁,作用是用来做什么?以及使用细节
https://www.cnblogs.com/chenwenbiao/archive/2011/08/01/2123905.html
demo.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php $fp = fopen( "file_lock.txt" , "w" ); //加锁 if (flock($fp, LOCK_EX)) { fwrite($fp, "abc\n" ); sleep(10); fwrite($fp, "ddd\n" ); echo 1; //执行完成解锁 flock($fp, LOCK_UN); } // 关闭文件 fclose($fp); |
lock.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package main import ( "syscall" "os" "log" "time" ) func main() { f, err := os.OpenFile( "file_lock.txt" , os.O_RDWR, 0777) if err != nil { log.Println( "open file err:" , err) } for { err = syscall.Flock(int(f.Fd()), syscall.LOCK_SH|syscall.LOCK_NB) if err != nil { log.Println( "flock err:" , err) log.Println( "flock err:" , syscall.EWOULDBLOCK ) } else { log.Println( "lock success" ) return } time.Sleep(time.Second) } } |
开窗口一执行: php demo.php
开窗口二执行: go lock.go
-------------------------------
bool flock ( int handle, int operation [, int &wouldblock] );
flock() 操作的 handle 必须是一个已经打开的文件指针。operation 可以是以下值之一:
- 要取得共享锁定(读取程序),将 operation 设为 LOCK_SH(PHP 4.0.1 以前的版本设置为 1)
- 要取得独占锁定(写入程序),将 operation 设为 LOCK_EX(PHP 4.0.1 以前的版本中设置为 2)
- 要释放锁定(无论共享或独占),将 operation 设为 LOCK_UN(PHP 4.0.1 以前的版本中设置为 3)
- 如果你不希望 flock() 在锁定时堵塞,则给 operation 加上 LOCK_NB(PHP 4.0.1 以前的版本中设置为 4)
建两个文件
(1) a.php
$file = "temp.txt" ; $fp = fopen ( $file , 'w' ); if ( flock ( $fp , LOCK_EX)){ fwrite( $fp , "abc\n" ); sleep(10); fwrite( $fp , "123\n" ); flock ( $fp , LOCK_UN); } fclose( $fp ); |
(2) b.php
$file = "temp.txt" ; $fp = fopen ( $file , 'r' ); echo fread ( $fp , 100); fclose( $fp ); |
运行 a.php 后,马上运行 b.php ,可以看到输出:
abc
等 a.php 运行完后运行 b.php ,可以看到输出:
abc
123
显然,当 a.php 写文件时数据太大,导致时间比较长时,这时 b.php 读取数据不完整
修改 b.php 为:
$file = "temp.txt" ; $fp = fopen ( $file , 'r' ); if ( flock ( $fp , LOCK_EX)){ echo fread ( $fp , 100); flock ( $fp , LOCK_UN); } else { echo "Lock file failed...\n" ; } fclose( $fp ); |
运行 a.php 后,马上运行 b.php ,可以发现 b.php 会等到 a.php 运行完成后(即 10 秒后)才显示:
abc
123
读取数据完整,但时间过长,他要等待写锁释放。
修改 b.php 为:
$file = "temp.txt" ; $fp = fopen ( $file , 'r' ); if ( flock ( $fp , LOCK_SH | LOCK_NB)){ echo fread ( $fp , 100); flock ( $fp , LOCK_UN); } else { echo "Lock file failed...\n" ; } fclose( $fp ); |
运行 a.php 后,马上运行 b.php ,可以看到输出:
Lock file failed…
证明可以返回锁文件失败状态,而不是向上面一样要等很久。
结论:
建议作文件缓存时,选好相关的锁,不然可能导致读取数据不完整,或重复写入数据。
file_get_contents 好像选择不了锁,不知道他默认用的什么锁,反正和不锁得到的输出一样,是不完整的数据。
我是要做文件缓存,所以只需要知道是否有写锁存在即可,有的话就查数据库就可以了。
测试环境:Linux(Ubuntu 6) , PHP 5.1.2 , Apache 2
再转:
文件的锁一般这么使用:
- $fp = fopen("filename", "a");
- flock($fp, LOCK_SH) or die("lock error")
- $str = fread($fp, 1024);
- flock($fp, LOCK_UN);
- fclose($fp);
注意fwrite之后,文件立即就被更新了,而不是等fwrite然后fclose之后文件才会更新,这个可以通过在fwrite之后fclose之前读取这个文件进行检查
但是什么时候使用lock_ex什么时候使用lock_sh呢?
读的时候:
如果不想出现dirty数据,那么最好使用lock_sh共享锁。可以考虑以下三种情况:
1. 如果读的时候没有加共享锁,那么其他程序要写的话(不管这个写是加锁还是不加锁)都会立即写成功。如果正好读了一半,然后被其他程序给写了,那么读的后一半就有可能跟前一半对不上(前一半是修改前的,后一半是修改后的)
2. 如果读的时候加上了共享锁(因为只是读,没有必要使用排他锁),这个时候,其他程序开始写,这个写程序没有使用锁,那么写程序会直接修改这个文件,也会导致前面一样的问题
3. 最理想的情况是,读的时候加锁(lock_sh),写的时候也进行加锁(lock_ex),这样写程序会等着读程序完成之后才进行操作,而不会出现贸然操作的情况
写的时候:
如果多个写程序不加锁同时对文件进行操作,那么最后的数据有可能一部分是a程序写的,一部分是b程序写的
如果写的时候加锁了,这个时候有其他的程序来读,那么他会读到什么东西呢?
1. 如果读程序没有申请共享锁,那么他会读到dirty的数据。比如写程序要写a,b,c三部分,写完a,这时候读读到的是a,继续写b,这时候读读到的是ab,然后写c,这时候读到的是abc.
2. 如果读程序在之前申请了共享锁,那么读程序会等写程序将abc写完并释放锁之后才进行读。
还有一篇也写得不错的博文:
-------------------------------
File locking in Linux
Table of contents
Introduction
File locking is a mutual-exclusion mechanism for files. Linux supports two major kinds of file locks:
- advisory locks
- mandatory locks
Below we discuss all lock types available in POSIX and Linux and provide usage examples.
Advisory locking
Traditionally, locks are advisory in Unix. They work only when a process explicitly acquires and releases locks, and are ignored if a process is not aware of locks.
There are several types of advisory locks available in Linux:
- BSD locks (flock)
- POSIX record locks (fcntl, lockf)
- Open file description locks (fcntl)
All locks except the lockf
function are reader-writer locks, i.e. support exclusive and shared modes.
Note that flockfile
and friends have nothing to do with the file locks. They manage internal mutex of the FILE
object from stdio.
Reference:
- File Locks, GNU libc manual
- Open File Description Locks, GNU libc manual
- File-private POSIX locks, an LWN article about the predecessor of open file description locks
Common features
The following features are common for locks of all types:
- All locks support blocking and non-blocking operations.
- Locks are allowed only on files, but not directories.
- Locks are automatically removed when the process exits or terminates. It’s guaranteed that if a lock is acquired, the process acquiring the lock is still alive.
Differing features
This table summarizes the difference between the lock types. A more detailed description and usage examples are provided below.
BSD locks | lockf function | POSIX record locks | Open file description locks | |
---|---|---|---|---|
Portability | widely available | POSIX (XSI) | POSIX (base standard) | Linux 3.15+ |
Associated with | File object | [i-node, pid] pair | [i-node, pid] pair | File object |
Applying to byte range | no | yes | yes | yes |
Support exclusive and shared modes | yes | no | yes | yes |
Atomic mode switch | no | - | yes | yes |
Works on NFS (Linux) | Linux 2.6.12+ | yes | yes | yes |
File descriptors and i-nodes
A file descriptor is an index in the per-process file descriptor table (in the left of the picture). Each file descriptor table entry contains a reference to a file object, stored in the file table (in the middle of the picture). Each file object contains a reference to an i-node, stored in the i-node table (in the right of the picture).
A file descriptor is just a number that is used to refer a file object from the user space. A file object represents an opened file. It contains things likes current read/write offset, non-blocking flag and another non-persistent state. An i-node represents a filesystem object. It contains things like file meta-information (e.g. owner and permissions) and references to data blocks.
File descriptors created by several open()
calls for the same file path point to different file objects, but these file objects point to the same i-node. Duplicated file descriptors created by dup2()
or fork()
point to the same file object.
A BSD lock and an Open file description lock is associated with a file object, while a POSIX record lock is associated with an [i-node, pid]
pair. We’ll discuss it below.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2020-04-26 【转】上传进度----PHP大文件分割上传(分片上传)
2018-04-26 【转】supervisord使用
2018-04-26 手动安装pip
2017-04-26 ubuntu 中 iptables 和 ufw 的关系
2016-04-26 javascript 函数 add(1)(2)(3)(4)实现无限极累加 —— 一步一步原理解析
2016-04-26 不动笔墨不读书
2016-04-26 html5 canvas 实现简单的画图