1
import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()
def do_thing(job_id):
    _mainlock.acquire() #Dictionary modification lock acquire
    _job_locks.setdefault(job_id, threading.RLock()) #Possibly modifies the dictionary
    _mainlock.release()
    _job_locks[job_id].acquire()
    try:
        one_time_init(job_id)
    finally:
        _job_locks[job_id].release()
    #On function return, the weakref.WeakValueDictionary should cause the key to evaporate

假设 do_thing() 在许多 id 编号可能相同也可能不同的线程上被多次调用(例如,4 次 ID 为 3,各有一次 ID 不同),这个线程安全吗?one_time_init() 是否会一次针对特定的作业 ID 运行多次?(PS:one_time_init 保存每个 ID 运行一次的状态,因此如果它已经运行完成,则调用它是无操作的)


更新代码(感谢 THC4k):

import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()

def do_thing(job_id):
    with _mainlock:
        jl = _job_locks.setdefault(job_id, threading.RLock())
    with jl:
        one_time_init(job_id)
4

1 回答 1

4

看起来安全。如果它运行了,为什么你甚至需要_job_locks再次检查它?one_time_init您可以在那里添加锁。为什么RLock而不是Lock(该功能似乎永远不会重新输入)?

无论如何,该with声明看起来更好:

import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()

def do_thing(job_id):
    with _mainlock:
        _job_locks.setdefault(job_id, threading.RLock())
    with _job_locks[job_id]:
        one_time_init(job_id)
于 2010-07-23T15:19:35.213 回答