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