多线程资源访问 - 我在哪里放锁?

时间:2009-01-15 19:09:14

标签: python multithreading locking

我有线程代码,每个线程需要写入同一个文件。为了防止并发问题,我使用的是Lock对象。

我的问题是我是否正确使用了锁。如果我从每个线程中设置锁定,该锁定是全局锁定还是仅特定于该特定线程?

基本上,我应该首先创建一个Lock并将其引用传递给每个线程,还是可以像我在这里一样从线程中设置它:

import time
from threading import Thread, Lock

def main():
    for i in range(20):
        agent = Agent(i)
        agent.start()

class Agent(Thread):
    def __init__(self, thread_num):
        Thread.__init__(self)
        self.thread_num = thread_num

    def run(self):
        while True:
            print 'hello from thread %s' % self.thread_num
            self.write_result()   

    def write_result(self):
        lock = Lock()
        lock.acquire()
        try:
            f = open('foo.txt', 'a')
            f.write('hello from thread %s\n' % self.thread_num)
            f.flush()
            f.close()
        finally:
            lock.release()

if __name__ == '__main__':
    main()

7 个答案:

答案 0 :(得分:6)

对于您的用例,一种方法可能是编写一个锁定的file子类:

class LockedWrite(file):
    """ Wrapper class to a file object that locks writes """
    def __init__(self, *args, **kwds):
        super(LockedWrite, self).__init__(*args, **kwds)
        self._lock = Lock()

    def write(self, *args, **kwds):
        self._lock.acquire()
        try:
            super(LockedWrite, self).write(*args, **kwds)
        finally:
            self._lock.release()

要在代码中使用,只需替换以下函数:

def main():
    f = LockedWrite('foo.txt', 'a')

    for i in range(20):
        agent = Agent(i, f)
        agent.start()

class Agent(Thread):
    def __init__(self, thread_num, fileobj):
        Thread.__init__(self)
        self.thread_num = thread_num
        self._file = fileobj    

#   ...

    def write_result(self):
        self._file.write('hello from thread %s\n' % self.thread_num)

这种方法将文件锁定放在文件本身,这似乎更清晰恕我直言

答案 1 :(得分:3)

在方法外创建锁。

class Agent(Thread):
    mylock = Lock()
    def write_result(self):
        self.mylock.acquire()
        try:
            ...
        finally:
            self.mylock.release()

或者如果使用python> = 2.5:

class Agent(Thread):
    mylock = Lock()
    def write_result(self):
        with self.mylock:
            ...

要在python 2.5中使用它,必须从以后导入语句:

from __future__ import with_statement

答案 2 :(得分:1)

lock()方法为每次调用返回一个锁定对象。所以每个线程(实际上每次调用write_result)都会有一个不同的锁对象。并且没有锁定。

答案 3 :(得分:1)

所使用的锁需要对所有线程都是通用的,或者至少确保两个锁不能同时锁定同一个资源。

答案 4 :(得分:1)

锁实例应该与文件实例相关联。

换句话说,您应该同时创建锁和文件,并将它们传递给每个线程。

答案 5 :(得分:1)

通过将单个线程(可能专门为此目的创建)指定为写入文件的唯一线程,并让所有其他线程委托给文件,您可以稍微简化一些事情(以稍微增加的开销为代价) -writer将要添加到文件中的字符串放入queue.Queue对象中。

队列内置了所有锁定功能,因此任何线程都可以随时安全地调用Queue.put()。文件编写器将是唯一调用Queue.get()的线程,并且可能大部分时间阻塞该调用(具有合理的超时以允许线程干净地响应关闭请求)。所有同步问题都将由Queue处理,您将不必担心是否忘记了某些锁定获取/释放... :)

答案 6 :(得分:0)

我很确定锁需要是每个线程的同一个对象。试试这个:

import time
from threading import Thread, Lock

def main():
    lock = Lock()
    for i in range(20):
        agent = Agent(i, lock)
        agent.start()

class Agent(Thread, Lock):
    def __init__(self, thread_num, lock):
        Thread.__init__(self)
        self.thread_num = thread_num
        self.lock = lock

    def run(self):
        while True:
            print 'hello from thread %s' % self.thread_num
            self.write_result()   

    def write_result(self):
        self.lock.acquire()
        try:
            f = open('foo.txt', 'a')
            f.write('hello from thread %s\n' % self.thread_num)
            f.flush()
            f.close()
        finally:
            lock.release()

if __name__ == '__main__':
    main()