V o s a m o


Python的文件锁使用

在python编程中,少不了对文件的操作,那么在并发情况下,多个进程如何对同一文件进行读写操作呢?这就要用到文件锁了。

关于文件锁的的知识,需要参考UNIX环境编程,这里只简要介绍概念。python的文件锁目前使用的是fcntl这个库,它实际上为 Unix上的ioctl,flock和fcntl 函数提供了一个接口。python通过调用fcntl.flock()函数对文件加锁。

对fcntl.flock()函数的说明:

linux的flock() 的函数原型如下所示:

int flock(int fd, int operation);

其中,参数fd表示文件描述符;参数operation指定要进行的锁操作,该参数的取值有如下几种:

  • LOCK_SH:表示要创建一个共享锁,在任意时间内,一个文件的共享锁可以被多个进程拥有;
  • LOCK_EX:表示创建一个排他锁,在任意时间内,一个文件的排他锁只能被一个进程拥有;
  • LOCK_UN:表示删除该进程创建的锁;
  • LOCK_MAND:它主要是用于共享模式强制锁,它可以与 LOCK_READ 或者 LOCK_WRITE联合起来使用,从而表示是否允许并发的读操作或者并发的写操作;

通常情况下,如果加锁请求不能被立即满足,那么系统调用flock()会阻塞当前进程。比如,进程想要请求一个排他锁,但此时,已经由其他进程获取了这个锁,那么该进程将会被阻塞。如果想要在没有获得这个排他锁的情况下不阻塞该进程,可以将LOCK_NB 和 LOCK_SH 或者 LOCK_EX 联合使用,那么系统就不会阻塞该进程。flock()所加的锁会对整个文件起作用。

示例代码

# coding=utf-8
import fcntl
import os, time
import uuid

FILE = "counter.txt"

if not os.path.exists(FILE):
    # create the counter file if it doesn't exist
    file = open(FILE, "w")
    vnc_line = '123cajfg: 127.0.0.1:15900'
    file.write(vnc_line + '\n')
    file.close()

for i in range(5):
    file = open(FILE, "a+")     #由于flock生成的是劝告锁,不能阻止进程对文件的操作,所以这里可以正常打开文件
    fcntl.flock(file.fileno(), fcntl.LOCK_EX)   #为了避免同时操作文件,需要程序自己来检查该文件是否已经被加锁。这里如果检查到加锁了,进程会被阻塞
    print 'acquire lock'
    now_port = int(file.readlines()[-1].split(':')[-1])
    new_port = now_port + 1
    token = str(uuid.uuid4())
    # file.seek(0)
    vnc_line = ':'.join([token, ' 127.0.0.1', str(new_port)])
    file.write(vnc_line + '\n')
    print os.getpid(), "=>", new_port
    time.sleep(10)
    file.close() # unlocks the file
    print 'release lock'
    time.sleep(2)

在多个终端中启动上面的程序,会发现它们相互阻塞。

注意:

  1. 对于文件的 close() 操作会使文件锁失效;
  2. 同理,进程结束后文件锁失效;
  3. flock() 的 LOCK_EX是“劝告锁”,系统内核不会强制检查锁的状态,需要在代码中进行文件操作的地方显式检查才能生效。

参考资料

vosamo /
Published under (CC) BY-NC-SA in categories 编程  tagged with python