本文目录导读:

flock命令(Linux/Unix 推荐)mkdir原子操作(通用所有系统)ln硬链接(避免竞态条件)lockfile命令(需安装 procmail)- PowerShell 中的文件锁(Windows)
- Python 中的文件锁
- 关键注意事项
- 推荐方案
利用操作系统提供的原子操作,确保只有一个进程能成功获取锁,以下是几种常见的方法:
flock 命令(Linux/Unix 推荐)
最常用且可靠的方法,通过文件描述符锁定文件。
#!/bin/bash
LOCK_FILE="/tmp/myapp.lock"
# 打开文件并获取文件描述符
exec 200>"$LOCK_FILE"
# 尝试获取锁(非阻塞)
flock -n 200 || {
echo "另一个实例正在运行,退出"
exit 1
}
# 或者使用阻塞等待
# flock 200 || exit 1
echo "获得锁,开始执行任务..."
sleep 30 # 模拟任务
echo "任务完成,释放锁"
# 脚本结束时自动释放锁(文件描述符关闭时)
关键点:
exec 200>"$LOCK_FILE":打开/创建文件,文件描述符200flock -n:非阻塞尝试(-n),失败立即返回- 锁在文件描述符关闭时自动释放
mkdir 原子操作(通用所有系统)
利用 mkdir 的原子性(要么成功创建,要么失败):
#!/bin/bash
LOCK_DIR="/tmp/myapp.lockdir"
# 尝试创建目录作为锁,mkdir是原子操作
if mkdir "$LOCK_DIR" 2>/dev/null; then
echo "获得锁,开始执行任务..."
trap "rmdir '$LOCK_DIR'; echo '锁已释放'" EXIT
sleep 30 # 模拟任务
else
echo "另一个实例正在运行,退出"
exit 1
fi
优点:跨平台(Linux/Windows/BSD都可使用)
缺点:需要手动清理(使用 trap 确保清理)
ln 硬链接(避免竞态条件)
ln 也是原子操作,比 mkdir 更可靠:
#!/bin/bash
LOCK_FILE="/tmp/myapp.lock"
PID=$$
LOCK_TARGET="/tmp/lock_target_$PID"
# 创建唯一临时文件
touch "$LOCK_TARGET"
# 尝试创建硬链接,如果文件已存在则失败
if ln "$LOCK_TARGET" "$LOCK_FILE" 2>/dev/null; then
echo "获得锁 $LOCK_FILE"
trap "rm -f '$LOCK_FILE' '$LOCK_TARGET'; echo '锁已释放'" EXIT
sleep 30 # 模拟任务
else
echo "另一个实例正在运行"
rm -f "$LOCK_TARGET"
exit 1
fi
lockfile 命令(需安装 procmail)
#!/bin/bash
LOCK_FILE="/tmp/myapp.lock"
# 创建锁文件(等待10秒超时)
lockfile -r -1 -l 3600 "$LOCK_FILE" 2>/dev/null || {
echo "无法获取锁(超时或权限问题)"
exit 1
}
echo "获得锁,开始执行..."
# 函数结束时自动删除锁
trap "rm -f $LOCK_FILE; exit" EXIT
sleep 30
PowerShell 中的文件锁(Windows)
$lockFile = "$env:TEMP\myscript.lock"
$lockStream = $null
try {
# 尝试打开文件,FileShare.None 表示独占访问
$lockStream = [System.IO.File]::Open(
$lockFile,
[System.IO.FileMode]::OpenOrCreate,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None
)
Write-Host "获得锁,开始执行..."
Start-Sleep -Seconds 30 # 模拟任务
}
catch {
Write-Host "另一个实例正在运行,退出"
exit 1
}
finally {
if ($lockStream -ne $null) {
$lockStream.Close()
Remove-Item $lockFile -Force -ErrorAction SilentlyContinue
}
}
Python 中的文件锁
import fcntl
import sys
import time
LOCK_FILE = "/tmp/myapp.lock"
def main():
# 打开/创建锁文件
with open(LOCK_FILE, 'w') as f:
try:
# fcntl.LOCK_EX: 排他锁, LOCK_NB: 非阻塞
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
print("获得锁,开始执行...")
# 执行任务
time.sleep(30)
print("任务完成,锁自动释放")
except IOError:
print("另一个实例正在运行,退出")
sys.exit(1)
if __name__ == "__main__":
main()
关键注意事项
- 原子操作:选择使用系统提供的原子操作(flock、mkdir、ln)
- 自动清理:使用
trap或finally确保锁文件在异常时也被清理 - 超时机制:防止死锁,如
flock -w 10等待10秒 - PID 验证:可将进程ID写入锁文件,检查进程是否存活:
# 检查锁文件中的PID是否还在运行 if [ -f "$LOCK_FILE" ]; then OLD_PID=$(cat "$LOCK_FILE") if kill -0 "$OLD_PID" 2>/dev/null; then echo "进程 $OLD_PID 还在运行" exit 1 else echo "清除过期锁" rm -f "$LOCK_FILE" fi fi echo $$ > "$LOCK_FILE"
推荐方案
- Linux/Unix 脚本:优先使用
flock方案(最可靠、最简洁) - 跨平台脚本:使用
mkdir方案 - Windows/PowerShell:使用 .NET 的文件流独占访问
- 需要复杂逻辑:使用 Python/Perl 等编程语言实现
选择合适的锁机制取决于你的操作系统和具体需求,关键是理解原子操作和自动释放这两个核心概念。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播