python条件锁

时间:2009-03-09 09:03:54

标签: python multithreading

如何在线程应用程序中实现条件锁,例如我就是 30个线程正在调用函数,并且对于大多数时间而言,所有线程都可以同时访问,但是根据函数输入,当只有一个线程可以执行该操作时,可能存在条件。 (如果重复输入值并且某些线程仍在工作,那么我需要锁定。)

我现在有使用Rlock()的模块线程,但我现在不知道如何以我在第一部分描述它的方式使用它。

编辑:问题实际上是关于如何防止任何两个线程同时使用相同的参数运行相同的函数。 (感谢大卫帮助我制定我的问题:))

2 个答案:

答案 0 :(得分:5)

试试这个:在你的函数所在的模块中有一个锁,如果函数的输入是需要锁定的,那么获取函数内部的锁。否则不要。

l = threading.RLock()

def fn(arg):
    if arg == arg_that_needs_lock:
        l.acquire()
        try:
            # do stuff
        finally:
            l.release()
    else:
        # do other stuff

修改

据我现在所知,问题实际上是关于如何防止任何两个线程同时使用相同的参数运行相同的函数。但是,两个线程同时运行具有不同参数的相同函数没有问题。如果函数的所有有效参数都可以是字典键,那么执行此操作的简单方法是创建锁的参数字典:

import threading

dict_lock = threading.RLock()
locks = {}

def fn_dict(arg):
    dict_lock.acquire()
    try:
        if arg not in dict:
            locks[arg] = threading.RLock()
        l = locks[arg]
    finally:
        dict_lock.release()
    l.acquire()
    try:
        # do stuff
    finally:
        l.release()

如果你的函数可以使用许多不同的参数调用,那么这相当于很多锁。可能更好的方法是拥有一组函数当前正在执行的所有参数,并使该组的内容受到锁的保护。我认为这应该有效:

set_condition = threading.Condition()
current_args = set()

def fn_set(arg):
    set_condition.acquire()
    try:
        while arg in current_args:
            set_condition.wait()
        current_args.add(arg)
    finally:
        set_condition.release()
    # do stuff
    set_condition.acquire()
    try:
        current_args.remove(arg)
        set_condition.notifyAll()
    finally:
        set_condition.release()

答案 1 :(得分:1)

听起来你想要类似于Readers-Writer lock的东西。

这可能不是你想要的,但可能是一个线索:

from __future__ import with_statement
import threading

def RWLock(readers = 1, writers = 1):
    m = _Monitor(readers, writers)
    return (_RWLock(m.r_increment, m.r_decrement), _RWLock(m.w_increment, m.w_decrement))

class _RWLock(object):
    def __init__(self, inc, dec):
        self.inc = inc
        self.dec = dec

    def acquire(self):
        self.inc()
    def release(self):
        self.dec()
    def __enter__(self):
        self.inc()
    def __exit__(self):
        self.dec()

class _Monitor(object):
    def __init__(self, max_readers, max_writers):
        self.max_readers = max_readers
        self.max_writers = max_writers
        self.readers = 0
        self.writers = 0
        self.monitor = threading.Condition()

    def r_increment(self):
        with self.monitor:
            while self.writers > 0 and self.readers < self.max_readers:
                self.monitor.wait()
            self.readers += 1
            self.monitor.notify()

    def r_decrement(self):
        with self.monitor:
            while self.writers > 0:
                self.monitor.wait()
            assert(self.readers > 0)
            self.readers -= 1
            self.monitor.notify()

    def w_increment(self):
        with self.monitor:
            while self.readers > 0 and self.writers < self.max_writers:
                self.monitor.wait()
            self.writers += 1
            self.monitor.notify()

    def w_decrement(self):
        with self.monitor:
            assert(self.writers > 0)
            self.writers -= 1
            self.monitor.notify()

if __name__ == '__main__':

    rl, wl = RWLock()
    wl.acquire()
    wl.release()
    rl.acquire()
    rl.release()

(遗憾的是未经测试)