私は、サードパーティソリューションからデータを受信し、データベースに保存し、別のサードパーティソリューションで使用するためにデータを調整するソフトウェアの更新プログラムの作成に取り組んでいるジュニア開発者です。当社のソフトウェアはWindowsサービスとして実行されます。
以前のバージョンのコードを見ると、次のように表示されます。
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach(int SomeObject in ListOfObjects)
{
lock (_workerLocker)
{
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
}
// check to see if the service has been stopped. If yes, then exit
if (this.IsRunning() == false)
{
break;
}
lock (_workerLocker)
{
_runningWorkers++;
}
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
ロジックは明確なようです:スレッドプールに空きができるまで待ち、サービスが停止していないことを確認してから、スレッドカウンターをインクリメントし、作業をキューに入れます。_runningWorkers
内側にデクリメントされSomeMethod()
内部のlock
その後の呼び出し、そのステートメントMonitor.Pulse(_workerLocker)
。
私の質問はlock
、次のように
、単一の内にすべてのコードをグループ化することの利点があります:
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach (int SomeObject in ListOfObjects)
{
// Is doing all the work inside a single lock better?
lock (_workerLocker)
{
// wait for room in ThreadPool
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
// check to see if the service has been stopped.
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
_runningWorkers++;
}
else
{
break;
}
}
}
他のスレッドをもう少し待っているように見えるかもしれませんが、単一の論理ブロックで繰り返しロックするのも時間がかかるようです。ただし、マルチスレッドは初めてなので、ここでは気づいていない他の懸念があると思います。
_workerLocker
ロックされる他の唯一の場所は、SomeMethod()
であり、デクリメントの目的のためだけであり_runningWorkers
、その後、ログに記録して戻る前にのforeach
数が_runningWorkers
ゼロになるのを待つために外にあります。
助けてくれてありがとう。
編集4/8/15
セマフォの使用を推奨してくれた@delnanに感謝します。コードは次のようになります。
static int MaxSimultaneousThreads = 5;
static Semaphore WorkerSem = new Semaphore(MaxSimultaneousThreads, MaxSimultaneousThreads);
foreach (int SomeObject in ListOfObjects)
{
// wait for an available thread
WorkerSem.WaitOne();
// check if the service has stopped
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
else
{
break;
}
}
WorkerSem.Release()
内部で呼び出されSomeMethod()
ます。
SomeMethod
非同期で呼び出します。上記の「ロック」セクションは、新しいスレッドSomeMethod
が実行を開始する前、または少なくともすぐ後に残されます。
Monitor.Wait()
別のリソース(SomeMethod
この場合は)がロックを使用できるように、ロックを解除して再取得することが目的であると理解しています。反対側でSomeMethod
は、ロックを取得し、カウンターをデクリメントしてMonitor.Pulse()
から、問題のメソッドにロックを返す呼び出しを行います。繰り返しますが、これは私自身の理解です。
Monitor.Wait
、ロックを解除します。ドキュメントをご覧になることをお勧めします。