本文目录导读:

PHP 文件锁主要通过 flock() 函数实现,可以防止多个进程同时修改同一文件导致的数据竞争问题。
基本用法
简单文件锁示例
<?php
// 打开文件
$fp = fopen('data.txt', 'r+');
if ($fp === false) {
die("无法打开文件");
}
// 获取独占锁(写锁)
if (flock($fp, LOCK_EX)) {
// 读取文件内容
$content = file_get_contents('data.txt');
// 执行写入操作
file_put_contents('data.txt', $content . "新数据\n");
// 释放锁
flock($fp, LOCK_UN);
} else {
echo "获取锁失败";
}
fclose($fp);
?>
完整的事务处理示例
<?php
class FileLock {
private $fp;
private $filepath;
public function __construct($filepath) {
$this->filepath = $filepath;
}
public function lock($mode = LOCK_EX) {
$this->fp = fopen($this->filepath, 'c+');
if ($this->fp === false) {
return false;
}
return flock($this->fp, $mode);
}
public function unlock() {
flock($this->fp, LOCK_UN);
fclose($this->fp);
}
}
// 使用示例
$lock = new FileLock('counter.txt');
if ($lock->lock()) {
// 读取当前值
$count = (int)file_get_contents('counter.txt');
// 执行更新
$count++;
// 写入新值
ftruncate($lock->fp, 0); // 清除文件内容
fwrite($lock->fp, $count);
// 释放锁
$lock->unlock();
echo "计数器值: " . $count;
}
?>
锁类型详解
共享锁(读锁)
<?php
// 多个进程可以同时读取
$fp = fopen('data.txt', 'r');
if (flock($fp, LOCK_SH)) {
echo "获得共享锁,可以读取文件\n";
$content = file_get_contents('data.txt');
echo $content;
flock($fp, LOCK_UN);
}
fclose($fp);
?>
独占锁(写锁)
<?php
// 同一时间只有一个进程可以写入
$fp = fopen('data.txt', 'w');
if (flock($fp, LOCK_EX)) {
echo "获得独占锁,阻塞其他写入\n";
// 写入操作
fwrite($fp, "新数据内容");
flock($fp, LOCK_UN);
}
fclose($fp);
?>
非阻塞锁
<?php
$fp = fopen('data.txt', 'r+');
// 非阻塞模式
if (flock($fp, LOCK_EX | LOCK_NB)) {
echo "立即获得锁\n";
// 执行操作
flock($fp, LOCK_UN);
} else {
echo "文件已被锁定,跳过操作\n";
}
fclose($fp);
?>
实用场景示例
计数器应用
<?php
function incrementCounter($file) {
$fp = fopen($file, 'c+');
if (!$fp) return false;
if (flock($fp, LOCK_EX)) {
// 读取当前值
$current = (int)fread($fp, filesize($file) ?: 1);
// 增加计数器
$current++;
// 重置文件指针并写入新值
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, $current);
flock($fp, LOCK_UN);
fclose($fp);
return $current;
}
fclose($fp);
return false;
}
// 多进程并发调用
echo "计数结果: " . incrementCounter('counter.txt');
?>
日志写入器
<?php
class LogWriter {
private $file;
public function __construct($file) {
$this->file = $file;
}
public function write($message) {
$fp = fopen($this->file, 'a');
if ($fp === false) return false;
// 尝试获取锁(最多等待10秒)
$timeout = 10;
$startTime = time();
while (!flock($fp, LOCK_EX)) {
if ((time() - $startTime) > $timeout) {
fclose($fp);
return false;
}
usleep(100000); // 100ms
}
// 写入日志
$logEntry = '[' . date('Y-m-d H:i:s') . '] ' . $message . "\n";
fwrite($fp, $logEntry);
// 释放锁并关闭
flock($fp, LOCK_UN);
fclose($fp);
return true;
}
}
// 使用示例
$logger = new LogWriter('app.log');
$logger->write('用户登录成功');
?>
配置文件更新
<?php
function updateConfig($file, $key, $value) {
$fp = fopen($file, 'r+');
if (!$fp) return false;
if (flock($fp, LOCK_EX)) {
// 读取并解析当前配置
$content = fread($fp, filesize($file));
$config = json_decode($content, true);
// 更新配置
$config[$key] = $value;
// 写回文件
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, json_encode($config));
flock($fp, LOCK_UN);
fclose($fp);
return true;
}
fclose($fp);
return false;
}
// 使用示例
updateConfig('config.json', 'timeout', 30);
?>
注意事项
锁的作用域
<?php
// 注意:锁只在当前文件操作期间有效
function badLockExample() {
$fp = fopen('data.txt', 'r+');
flock($fp, LOCK_EX);
// 其他操作
$content = file_get_contents('data.txt'); // 这个不受锁保护
// 因为 file_get_contents 是独立操作
fclose($fp); // 关闭文件会自动释放锁
}
// 正确的做法
function goodLockExample() {
$fp = fopen('data.txt', 'r+');
flock($fp, LOCK_EX);
// 使用同一文件指针进行读写
rewind($fp);
$content = stream_get_contents($fp);
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, $content . "新数据");
fclose($fp); // 自动释放锁
}
?>
超时处理
<?php
function getLockWithTimeout($fp, $timeout = 5) {
$start = microtime(true);
while (!flock($fp, LOCK_EX | LOCK_NB)) {
if (microtime(true) - $start > $timeout) {
throw new Exception("获取锁超时");
}
usleep(100000); // 等待100ms
}
return true;
}
?>
最佳实践
<?php
class SafeFileOperation {
private $file;
public function __construct($file) {
$this->file = $file;
}
public function safeWrite($callback) {
$fp = fopen($this->file, 'c+');
if (!$fp) throw new Exception("无法打开文件");
try {
if (flock($fp, LOCK_EX)) {
// 执行回调函数
$result = $callback($fp);
// 释放锁
flock($fp, LOCK_UN);
return $result;
}
throw new Exception("无法获取文件锁");
} finally {
fclose($fp);
}
}
}
// 使用示例
$fileOp = new SafeFileOperation('data.txt');
$result = $fileOp->safeWrite(function($fp) {
// 安全的文件操作
$content = stream_get_contents($fp);
rewind($fp);
ftruncate($fp, 0);
fwrite($fp, $content . "新内容");
return true;
});
?>
性能优化建议
- 尽量减少锁持有时间:只锁定必要的操作
- 合理使用锁类型:读操作使用
LOCK_SH,写操作使用LOCK_EX - 避免死锁:始终按照相同的顺序获取多个锁
- 使用非阻塞模式:在可能等待很长时间的场景使用
LOCK_NB
文件锁是处理并发问题的基本工具,但在高并发场景下,建议考虑使用数据库或 Redis 等专业的并发控制方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播