1人の王とn人の手先が彼に提出されている状況を想像してみてください。王が「One!」と言うと、ミニオンの1人が「Two!」と言いますが、そのうちの1人だけです。つまり、最速のミニオンだけが話し、他のミニオンは王の別の呼び出しを待たなければなりません。
これは私の試みです:
using System;
using System.Threading;
class Program {
static bool leaderGO = false;
void Leader() {
do {
lock(this) {
//Console.WriteLine("? {0}", leaderGO);
if (leaderGO) Monitor.Wait(this);
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
Monitor.Pulse(this);
}
} while(true);
}
void Follower (char chant) {
do {
lock(this) {
//Console.WriteLine("! {0}", leaderGO);
if (!leaderGO) Monitor.Wait(this);
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
Monitor.Pulse(this);
}
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
king.Start();
minion1.Start();
minion2.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
}
}
期待される出力は次のようになります(#と$は2つの異なるミニオンを表します):
> One!
# Two!
> One!
$ Two!
> One!
$ Two!
...
それらが表示される順序は重要ではなく、ランダムになります。ただし、問題は、このコードをコンパイルすると、代わりに次のように生成されることです。
> One!
# Two!
$ Two!
> One!
# Two!
> One!
$ Two!
# Two!
...
つまり、複数のミニオンが同時に話します。これはさらに多くの手先でかなりの混乱を引き起こすでしょう、そして王はこの種の干渉を許すべきではありません。
考えられる解決策は何でしょうか?
将来の読者のために、これが最終的な実用的なコードです:
using System;
using System.Threading;
class Program {
static AutoResetEvent leader = new AutoResetEvent(false);
static AutoResetEvent follower = new AutoResetEvent(false);
void Leader() {
do {
Console.WriteLine(" One!");
Thread.Sleep(300);
follower.Set(); // Leader allows a follower speak
leader.WaitOne(); // Leader waits for the follower to finish speaking
} while(true);
}
void Follower (char emblem) {
do {
follower.WaitOne(); // Follower waits for the leader to allow speaking
Console.WriteLine("{0} Two!", emblem);
leader.Set(); // Follower finishes speaking
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
Thread minion3 = new Thread(() => m.Follower('&'));
king.Start();
minion1.Start();
minion2.Start();
minion3.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
minion3.Abort();
}
}