現在、セマフォだけのスレッドセーフなスレッドプールを実装する必要がある教育用の課題に取り組んでいます。セマフォ実装のプロデューサ - コンシューマ指向のスレッドプール
Synchronize
wait
notify
sleep
などのスレッドセーフなAPIは使用しないでください。私が持っているコードにすぎ取得せずに、まず
:
- はスレッドセーフなキュー(ない2つのスレッドが同時に\デキューをキューイングすることはできません)(私は
ConcurrentLinkedQueue
で、この問題をテストしていると実装共有:
-
問題が
設計自体)持続します
Tasks
セマフォ= 0Available
セマフォ= 0Tasks_Queue
キューAvailable_Queue
キュー
ワーカースレッド:
Blocked
セマフォ= 0
一般情報:
のみマネージャ(シングルスレッド)
Tasks_Queue
とAvailable_Queue
のみのApp-メイン(シングルスレッド)をデキューできるタスクをキューに入れることができています
Tasks_Queue
各ワーカースレッドは、
Available_Queue
だから我々は、単一のプロデューサー、単一マネージャーといくつかの消費者が混在しています。
- アプリが最初に起動し、すぐに
Available_Queue
自体をエンキューますワーカースレッドのそれぞれを開始すると、Available
セマフォを解放し、それが個人的なBlocked
セマフォの取得ブロックされます。 - たびのApp-主マネージャは、それが最初の両方
Tasks
とAvailable
セマフォを取得しなければならない新しいタスクを実行したいときはいつでも、それはTask
セマフォ - を解放し、新しいタスクをキューに入れます。
私の質問:アプリケーションの実行時に
セマフォは、使用可能なワーカースレッドが存在しないことが知られているとき、キューへのアクセスを保護するために設置されていても、ヌルの労働者を返すdequeue_worker()
機能を。
ヌルスレッドを描画する場合、再帰的にdequeue_worker()
を呼び出して問題を解決しましたが、セマフォーの許可を永久に失うことを想定しています。しかし、私が労働者の数を1に制限すると、労働者は永遠にブロックされません。
1)オリジナルデザインのブレークポイントは何ですか?
2)私の "ソリューション"がデザインをさらに壊すことはありませんか?
コードスニペット:
// only gets called by Worker threads: enqueue_worker(this);
private void enqueue_worker(Worker worker) {
available_queue.add(worker);
available.release();
}
// only gets called by App-Main (a single thread)
public void enqueue_task(Query query) {
tasks_queue.add(query);
tasks.release();
}
// only gets called by Manager(a single Thread)
private Worker dequeue_worker() {
Worker worker = null;
try {
available.acquire();
worker = available_queue.poll();
} catch (InterruptedException e) {
// shouldn't happen
} // **** the solution: ****
if (worker==null) worker = dequeue_worker(); // TODO: find out why
return worker;
}
// only gets called by Manager(a single Thread)
private Query dequeue_task() {
Query query = null;
try {
tasks.acquire();
query = tasks_queue.poll();
} catch (InterruptedException e) {
// shouldn't happen
}
return query;
}
// gets called by Manager (a single thread)
private void execute() { // check if task is available and executes it
Worker worker = dequeue_worker(); // available.down()
Query query = dequeue_task(); //task.down()
worker.setData(query);
worker.blocked.release();
}
そして最後に労働者Run()
方法:あなたがメインループでenqueue_worker
、二時間に1回、2回available.release()
を呼び出している
while (true) { // main infinite loop
enqueue_worker(this);
acquire(); // blocked.acquire();
<C.S>
available.release();
}
スレッドセーフではありません。私のブロック機構は 'Available'と' Tasks'セマフォを使って実装されています –
あなたの再帰的反復は同じですが、非常に非効率的です – hoaz
availlable.acquire()呼び出しはnullオブジェクトの.poll() 。 –