Üçüncü taraf bir çözümden veri alan, bir veritabanında depolayan ve ardından verileri başka bir üçüncü taraf çözüm tarafından kullanılmak üzere şartlandıran bir yazılım güncellemesi yazmaya çalışan küçük bir geliştiriciyim. Yazılımımız bir Windows servisi olarak çalışmaktadır.
Önceki sürümdeki koda bakarak, şunu görüyorum:
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);
}
Mantık açık görünüyor: İş parçacığı havuzunda odayı bekleyin, hizmetin durmadığından emin olun, sonra iş parçacığı sayacını artırın ve işi sıralayın. sonra çağıran bir cümlenin içinde _runningWorkers
azalır .SomeMethod()
lock
Monitor.Pulse(_workerLocker)
Sorum şu:
Tek içindeki tüm kod gruplama içinde bir yararı var mı lock
bunun gibi,:
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;
}
}
}
Öyle görünüyor ki, diğer iş parçacıkları için biraz daha fazla beklemeye neden olabilir, ancak daha sonra tek bir mantıksal blokta tekrar tekrar kilitlenmek gibi görünmesi de biraz zaman alabilir. Ancak, çok iş parçacıklı konusunda yeniyim, bu yüzden burada bilmediğim başka endişeler olduğunu varsayıyorum.
_workerLocker
Kilitli kalan diğer yerler SomeMethod()
sadece ve yalnızca azaltma amacıyladır _runningWorkers
ve daha sonra dışarıda loglama ve geri dönmeden önce foreach
sayının _runningWorkers
sıfıra gitmesini beklemek .
Herhangi bir yardım için teşekkürler.
EDIT 4/8/15
Bir semafor kullanmanız için @delnan'a teşekkür ederiz. Kod olur:
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()
içine denir SomeMethod()
.
SomeMethod
zaman uyumsuz olarak çağırır , yukarıdaki "kilit" bölümü yeni iş parçacığı çalışmaya SomeMethod
başladıktan önce veya en azından kısa bir süre sonra bırakılacaktır .
Monitor.Wait()
, kilidi başka bir kaynağın ( SomeMethod
bu durumda) kullanabilmesi için kilidi açmak ve yeniden elde etmek. Diğer taraftan SomeMethod
kilidi alır, sayacı azaltır ve sonra Monitor.Pulse()
kilidi söz konusu yönteme geri döndüren çağrılar . Yine, bu benim kendi anlayışım.
Monitor.Wait
kilidi serbest bırakır. Dokümanlara bir göz atmanızı öneririm.