Üçü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 _runningWorkersazalır .SomeMethod()lockMonitor.Pulse(_workerLocker)
Sorum şu:
Tek içindeki tüm kod gruplama içinde bir yararı var mı lockbunun 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.
_workerLockerKilitli kalan diğer yerler SomeMethod()sadece ve yalnızca azaltma amacıyladır _runningWorkersve daha sonra dışarıda loglama ve geri dönmeden önce foreachsayının _runningWorkerssı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().
SomeMethodzaman uyumsuz olarak çağırır , yukarıdaki "kilit" bölümü yeni iş parçacığı çalışmaya SomeMethodbaş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 ( SomeMethodbu durumda) kullanabilmesi için kilidi açmak ve yeniden elde etmek. Diğer taraftan SomeMethodkilidi 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.Waitkilidi serbest bırakır. Dokümanlara bir göz atmanızı öneririm.