如果之前有人问过,请原谅我。我经常环顾四周,但我觉得我没有足够的词汇来搜索网页。
我在python中有一个多线程应用程序。我希望能够锁定某个代码块,但只能锁定具有特定条件的其他线程。让我举个例子:有三个主题,thread_a
,thread_b
和thread_c
。每个线程可以随时运行函数foo
。我不希望bar
彼此相等的任何两个帖子能够同时访问Code block ALPHA
。但是,我不想阻止bar
值不同的线程。在这种情况下,我们先说thread_a
有bar == "cat"
并首先点击(3)
行。在thread_a
点击行(5)
之前,让我们说thread_b
,bar == "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
答案 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]