python 加锁_Python 中给文档加锁——fcntl

在 Python 中,如果想要给一个文档加锁,可以使用 fcntl 模块。其中有 flock 和 lockf 两种不同的方式。首先我们先了解一下在 Linux 中的文档锁。

Linux 中的文档锁

在 Linux 中,flock 和 fcntl 都是系统调用,而 lockf 则是库函数。lockf 则是 fcntl 的封装,因此 lockf 和 fcntl 在底层实现是一样的,对文档加锁的效果也是一样的。

首先说一些概念:

文档锁:针对整个文档的锁,如 flock。

记录锁:针对整个文档和文档部分字节的锁,如 fcntl、lockf。

排他锁:也可以称为写锁、独占锁,同一时间只有一个进程可以加锁。

共享锁:也可以称为读锁,支持多个进程并发读文档内容,但不可以写。

睡眠锁:一般和等待队列同时存在,当无法获取锁的时候会在等待队列中睡眠,直到满足条件被唤醒,如 semaphore、mutex。

自旋锁:自旋锁在被持有时,其它进程再申请时将不断”自旋”,不会陷入睡眠,直到持有者释放。为保证性能,自旋锁不应被持有时间过长。

劝告锁(建议锁):不要求进程一定要遵守,是一种约定俗成的规则,某进程持有建议锁的时候,其它进程依然可以强制操作,如 flock、fcntl。

强制锁:是内核行为,在系统调用违反约束条件时,内核将直接阻拦,如 fcntl(fcntl也可实现强制锁,但不建议使用)。

flock

函数:flock(fd, operation)

fd 是系统调用 open 返回的文档描述符,operation 的可选项有:

LOCK_SH: 共享锁

LOCK_EX: 排他锁

LOCK_UN: 解锁

LOCK_NB: 非阻塞(与上述三种操作一起使用)

flock 和 lockf 的第一个区别是 flock 只能对整个文档进行上锁,而不能对文档的某一部分上锁,lockf 可以对文档的某个区域进行上锁。

第二个区别是 flock 只能产生劝告性锁。flock 可以有共享锁和排他锁,而 lockf 只支持排他锁。

第三个区别主要是在使用 fork/dup 的情况。

第四个区别是 flock 不能在 NFS 文档系统上使用,要在 NFS 上使用需要用 fcntl。

lockf 和 fcntl

函数:

12345678910

int fcntl(int fd, int ⌘, ... /* arg */ );

struct flock {

...

short l_type;/* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */

short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */

off_t l_start; /* Starting offset for lock */

off_t l_len; /* Number of bytes to lock */

pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */

...

};

相关的 cmd 有三种:

F_SETLK: 设置文档锁(非阻塞)

F_SETLKW: 设置文档锁(阻塞)

F_GETLK: 获取锁信息,会修改我们传入的 struct flock。

fcntl/lockf 的特性有:

上锁可以递归。

加读锁(共享锁)必须是读打开的,加写锁(排他锁)文档必须是写打开的。

由 fork 产生的子进程不继承父进程所设置的锁。

支持强制性锁:对一个特定文档打开其设置组ID位(S_ISGID),并关闭其组执行位(S_IXGRP),则对该文档开启了强制性锁机制。再Linux中如果要使用强制性锁,则要在文档系统mount时,使用 -o mand 打开该机制。

使用 Python 中的 fcntl 模块

加密方式:

123456

import fcntl

fd = open("test") # flock 生成的是劝告锁,因此进程可以正常打开文档

fcntl.flock(fd, fcntl.LOCK_EX) # 检测文档是否被加锁。如果已经上了锁,那么这里就会被阻塞

fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) # 用 LOCK_NB 就不会被阻塞

fcntl.flock(fd.fcntl.LOCK_UN) # 对文档进行解锁

对文档 close 后文档锁会失效

进程结束后文档锁会失效

代码示例:

123456789101112131415161718192021222324

class SingleInstance:

def __init__(self):

file_path = os.path.abspath(__file__)

cur_dir = os.path.dirname(file_path)

self.lockfile = os.path.normpath(

cur_dir + '/' + os.path.basename(__file__))

if sys.platform != 'win32':

self.fp = open(self.lockfile, 'r')

try:

fcntl.flock(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)

except IOError:

print("Another instance is already running.")

sys.exit(-1)

else:

print("Other platforms are not supported.")

sys.exit(-1)

if __name__ == '__main__':

single = SingleInstance()

while True:

time.sleep(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值