0

オンデマンドのミラーリングを行う単純なサーバーがあります。フェッチは高価です (ネットワーク遅延、整合性チェック、(再) 圧縮など)。したがって、フェッチされる URL ごとに 1 つのロックを設定したいので、次のようにします。

  • 1 つのファイルをフェッチするスレッドは 1 つだけです。
  • 別のスレッドが現在フェッチされているファイルの 1 つを必要とする場合、ファイルの準備ができるまでブロックされます。

私は当初、次のようなことをしていました:

# Globals
fetching = dict()
fetch_lock = threading.Lock()

...

lock = None
do_fetch = False
with fetch_lock:
    if url in fetching:
        lock = fetching[url]
    else:
        lock = threading.Lock()
        fetching[url] = lock
        do_fetch = True

# Race condition
lock.acquire()

if do_fetch:
    ...

with fetch_lock:
    lock.release()
    if do_fetch:
        del fetching[url]

# Serve file
...

競合状態はかなりマイナーですが (スレッドがまだキャッシュにないファイルにアクセスしようとする可能性があります)、それを解決する方法が見つかりません。

4

1 に答える 1

1

この問題を解決するには、クリティカルセクションを作成している場合(他の誰もロックを持っていない場合)にクリティカルセクション内のロックを取得し、ロックがすでに存在する場合はクリティカルセクション外で取得します。

with fetch_lock:
    if url in fetching:
        lock = fetching[url]
    else:
        lock = threading.Lock()
        fetching[url] = lock
        do_fetch = True
        lock.acquire()
if not do_fetch:
    lock.acquire()

これにより、そこでの競合状態が解決されます。しかし、私が理解していないのは、ロックを作成するスレッドがロックテーブルからロックを削除する理由です。その後、新しいスレッドがファイルをフェッチしているときに、ファイルを提供するスレッドを作成できます。しかし、それはあなたが尋ねたものではありません。

于 2012-04-16T17:50:37.063 に答える