ฉันเป็นผู้พัฒนารุ่นน้องที่กำลังทำงานเกี่ยวกับการเขียนอัปเดตสำหรับซอฟต์แวร์ที่รับข้อมูลจากโซลูชันของบุคคลที่สามจัดเก็บไว้ในฐานข้อมูลจากนั้นกำหนดเงื่อนไขข้อมูลสำหรับการใช้งานโดยโซลูชันของ บริษัท อื่น ซอฟต์แวร์ของเราทำงานเป็นบริการ 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เป็น decremented ภายในSomeMethod()ภายในคำว่าสายแล้วlockMonitor.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ปลดล็อค ฉันแนะนำให้ดูเอกสาร