基于值的线程锁定

时间:2016-06-03 22:21:42

标签: python multithreading python-multithreading

如果之前有人问过,请原谅我。我经常环顾四周,但我觉得我没有足够的词汇来搜索网页。

我在python中有一个多线程应用程序。我希望能够锁定某个代码块,但只能锁定具有特定条件的其他线程。让我举个例子:有三个主题,thread_athread_bthread_c。每个线程可以随时运行函数foo。我不希望bar彼此相等的任何两个帖子能够同时访问Code block ALPHA。但是,我不想阻止bar值不同的线程。在这种情况下,我们先说thread_abar == "cat"并首先点击(3)行。在thread_a点击行(5)之前,让我们说thread_bbar == "cat"点击行(3)。我希望thread_b等待。但如果thread_c出现bar == "dog",我希望能够继续前进。

(1) def foo(bar):
(2)    
(3)     lock(bar)
(4)     # Code block ALPHA (two threads with equivalent bar should not be in here)
(5)     unlock(bar)

另外注意,bar的可能值完全不可预测但碰撞的可能性很高。

感谢您的帮助。我正在查看的图书馆是python threading library

3 个答案:

答案 0 :(得分:3)

<强>更新

好消息:我能够通过我拼凑在一起的粗略测试板重现您遇到的release_lock问题,并使用计数机制解决问题(如您所知) - 至少一个我可以告诉我的测试仪器。

现在使用两个单独的共享字典,一个用于跟踪与之前相关的“名称”或与每个锁相关联的值,另一个用于跟踪在给定时间使用每个字符串的线程数。

和以前一样,锁定名称必须是可散列的值,因此它们可以用作词典中的键。

import threading

namespace_lock = threading.Lock()
namespace = {}
counters = {}

def aquire_lock(value):
    with namespace_lock:
        if value in namespace:
            counters[value] += 1
        else:
            namespace[value] = threading.Lock()
            counters[value] = 1

    namespace[value].acquire()

def release_lock(value):
    with namespace_lock:
        if counters[value] == 1:
            del counters[value]
            lock = namespace.pop(value)
        else:
            counters[value] -= 1
            lock = namespace[value]

    lock.release()

# sample usage    
def foo(bar):
    aquire_lock(bar)
    # Code block ALPHA (two threads with equivalent bar should not be in here)
    release_lock(bar)

答案 1 :(得分:2)

在线程尝试进入或退出临界区时获取一个锁,并为with critical(bar): # Critical section. 的每个值使用单独的条件变量。以下内容可能会被优化以创建更少的条件变量,但是对于这个帖子这样做感觉就像是过早优化:

~

然后,每个想要进入临界区的线程都会执行以下操作:

name.sort

此代码未经测试,并行性很难,特别是锁和共享内存并行性。我不保证它会起作用。

答案 2 :(得分:0)

这是一个面向类的解决方案,适用于需要几个独立的锁组的情况。

# A dynamic group of locks, useful for parameter based locking.
class LockGroup(object):

    def __init__(self):
        self.lock_dict = {}
        self.lock = threading.Lock()

    # Returns a lock object, unique for each unique value of param.
    # The first call with a given value of param creates a new lock, subsequent
    # calls return the same lock.
    def get_lock(self, param):
        with self.lock:
            if param not in self.lock_dict:
                self.lock_dict[param] = threading.Lock()
            return self.lock_dict[param]