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 番号を持つ多くのスレッドで何度も呼び出されると仮定すると (たとえば、ID 3 で 4 回、異なる ID でそれぞれ 1 回)、このスレッドは安全ですか? one_time_init() は、特定のジョブ ID に対して一度に複数回実行されることはありますか? (PS: one_time_init は、ID ごとに 1 回実行された状態を保存するため、既に完了まで実行されている場合、呼び出しはノーオペレーションです)


更新されたコード (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_locksifone_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 に答える