実行に時間がかかる可能性があるスレッド間でグローバル静的変数を共有する必要があるマルチスレッド プログラム (C#) があります (WCF を使用して別のシステムにデータ要求を送信します)。問題は、lock ステートメントを使用しても、ThreadPool の外部で宣言されている場合、相互排除が保証されないように見えることです。
static void Main(string[] args)
{
public static int globalVar = 0;
public object locker;
System.Timers.Timer timer1 = new System.Timers.Timer(1000);
timer1.Elapsed += new ElapsedEventHandler(onTimer1ElapsedEvent);
timer1.Interval = 1000;
timer1.Enabled = true;
System.Timers.Timer timer2 = new System.Timers.Timer(500);
timer2.Elapsed += new ElapsedEventHandler(onTimer2ElapsedEvent);
timer2.Interval = 500;
timer2.Enabled = true;
}
public void onTimer1ElapsedEvent(object source, ElapsedEventArgs e)
{
lock (locker) {
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
globalVar = 1;
Console.WriteLine("Timer1 var = {0}", globalVar);
}));
}
}
public void onTimer2ElapsedEvent(object source, ElapsedEventArgs e)
{
lock (locker) {
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
globalVar = 2;
Thread.Sleep(2000); // simulates a WCF request that may take time
Console.WriteLine("Timer2 var = {0}", globalVar);
}));
}
}
したがって、ロックは機能せず、プログラムは出力できます: Timer2 var = 1
The lock ステートメントを ThreadPool 内に配置すると、問題が解決するようです。
public void onTimer1ElapsedEvent(object source, ElapsedEventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
lock (locker) {
globalVar = 1;
Console.WriteLine("Timer1 var = {0}", globalVar);
}
}));
}
public void onTimer2ElapsedEvent(object source, ElapsedEventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
lock (locker) {
globalVar = 2;
Thread.Sleep(2000); // simulates a WCF request that may take time
Console.WriteLine("Timer2 var = {0}", globalVar);
}
}));
}
ただし、2つのアプローチの違いと、同じ動作が得られない理由はわかりません。
また、2 番目のアプローチは相互排除の問題を解決しますが、timer1 スレッドは timer2 がロック ステートメントを終了するまで常に待機する必要があるため (これには時間がかかります)、私のプログラムではマルチスレッドの概念が機能しなくなります。共有変数を使用することと並行してマルチスレッド化を行うための最良の解決策は何ですか?