2009-01-15 57 views
5

我有线程代码,其中每个线程需要写入相同的文件。为了防止并发问题,我使用了一个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() 

回答

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 
+0

是的,你把它移到了方法之外,但你仍然在线程本身中创建它。这不是一个问题吗? – 2009-01-15 19:31:23

+0

@cgoldberd:它被创建为* class *属性,这意味着将为所有线程创建一个单独的属性。这是一个更好的地方,因为一切都停留在线程类上。陷入困境的是 – nosklo 2009-01-15 19:34:38

+0

。我喜欢那种方式 – 2009-01-15 19:37:32

1

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

1

所使用的锁定对于所有线程都必须是公共的,或者至少确保两个锁不能同时锁定相同的资源。

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() 
+0

-1:那不行。 – nosklo 2009-01-15 19:22:42

1

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

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

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) 

这种方法将文件锁定看起来更干净的文件本身IMHO

1

你可以通过指定一个简单的东西一点点(以稍微更多的开销为代价)简化一些东西d(可能是专门为此创建的)作为写入文件的唯一线程,并让所有其他线程通过将要添加到文件的字符串放入到文件写入器中,将其委托给文件写入器。

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

相关问题