การสิ้นสุดเธรด C # และเธรดเธรด ()


85

ใน MSDN คำอธิบายของเมธอด Thread.Abort () ระบุว่า: "การเรียกใช้เมธอดนี้มักจะยุติเธรด"

ทำไมไม่อยู่เสมอ?

ในกรณีใดบ้างที่ไม่ยุติเธรด

มีความเป็นไปได้อื่น ๆ ในการยุติเธรดหรือไม่

คำตอบ:


60

Thread.Abort()ฉีดThreadAbortExceptionบนด้าย Thread.ResetAbort()ด้ายอาจจะยกเลิกการร้องขอโดยการเรียก นอกจากนี้ยังมีโค้ดบางส่วนเช่นfinallyบล็อกที่จะดำเนินการก่อนที่จะจัดการข้อยกเว้น หากด้วยเหตุผลบางประการเธรดติดอยู่ในบล็อกดังกล่าวข้อยกเว้นจะไม่ถูกยกขึ้นบนเธรด

เนื่องจากผู้โทรสามารถควบคุมสถานะของเธรดได้น้อยมากเมื่อโทรAbort()โดยทั่วไปจึงไม่แนะนำให้ทำเช่นนั้น ส่งข้อความไปยังเธรดที่ขอยกเลิกแทน


ข้อความแบบไหน? คุณหมายถึงการเรียกใช้วิธีการหรือไม่?
user101375

4
ขึ้นอยู่กับว่าคุณส่งผ่านข้อมูลระหว่างเธรดของคุณอย่างไร เช่นถ้าเธรดของคุณเป็นเธรดของผู้ปฏิบัติงานที่มีคิวงานคุณสามารถจัดคิวข้อความ PleaseTerminate และปล่อยให้เธรดจัดการได้อย่างสง่างาม
Brian Rasmussen

เธรดของฉันมีปัญหาใหญ่อย่างหนึ่งที่เสาต้องแก้ไขคือไม่มีคิวงาน
user101375

อย่างที่บอกมันขึ้นอยู่กับว่ารหัสเธรดของคุณออกแบบมาอย่างไร บางทีคุณอาจส่งสัญญาณผ่านตัวแปรสมาชิกในตอนนั้น เป็นการยากที่จะเจาะจงมากขึ้นหากไม่มีรหัสจริง
Brian Rasmussen

54

ในกรณีใดบ้างที่ไม่ยุติเธรด

คำถามนี้ซ้ำกัน

เกิดอะไรขึ้นกับการใช้ Thread.Abort ()

มีความเป็นไปได้อื่น ๆ ในการยุติเธรดหรือไม่?

ใช่. ปัญหาของคุณคือคุณไม่ควรเริ่มต้นเธรดที่คุณไม่สามารถบอกอย่างสุภาพให้หยุดและมันจะหยุดในเวลาที่เหมาะสม หากคุณอยู่ในสถานการณ์ที่คุณต้องเริ่มเธรดที่อาจ (1) หยุดยาก (2) บั๊กกี้หรือเลวร้ายที่สุด (3) เป็นศัตรูกับผู้ใช้สิ่งที่ควรทำก็คือ กระบวนการใหม่เริ่มต้นเธรดในกระบวนการใหม่แล้วยุติกระบวนการเมื่อคุณต้องการให้เธรดหยุดทำงาน สิ่งเดียวที่สามารถรับประกันการยุติเธรดที่ไม่ให้ความร่วมมือได้อย่างปลอดภัยคือระบบปฏิบัติการที่จะหยุดกระบวนการทั้งหมด

ดูคำตอบที่ยาวเกินไปของฉันสำหรับคำถามนี้สำหรับรายละเอียดเพิ่มเติม:

ใช้คำสั่งล็อคภายในลูปใน C #

บิตที่เกี่ยวข้องคือบิตในตอนท้ายที่ฉันพูดถึงข้อควรพิจารณาเกี่ยวกับระยะเวลาที่คุณควรรอให้เธรดฆ่าตัวตายก่อนที่คุณจะยกเลิก


Eric ฉันควรบอกเธรดอย่างสุภาพอย่างไรให้หยุดหากเธรดนั้นกำลังรอออบเจ็กต์การซิงโครไนซ์เช่น EventWaitHandle.WaitOne ();?
Corvin

5
@Corvin: สัญญาระหว่างสองเธรดที่อธิบายว่าเธรดหนึ่งสื่อสารกับอีกเธรดหนึ่งอย่างไรขึ้นอยู่กับผู้เขียนโค้ดที่รันบนเธรดเหล่านั้น หากคุณมีข้อกำหนดว่า (1) เธรด X ต้องรอบนอ็อบเจกต์ที่เป็นไปได้ตลอดไปและ (2) เธรด Y นั้นต้องสามารถปิดเธรด X ได้อย่างหมดจดในระยะเวลาที่ จำกัด ฉันคิดว่าคุณมีข้อกำหนดที่ขัดแย้งกัน ตัดสินว่าใครชนะ ถ้าอดีตด้าย Y จะต้องรอ หากเป็นอย่างหลังเธรด X ไม่ควรรอตลอดไปควรรอสักครู่
Eric Lippert

ขอบคุณสำหรับคำตอบ. พิจารณาสถาปัตยกรรมต่อไปนี้: ฉันมีแอปพลิเคชันที่ต้องย่อขนาดตัวเองเมื่อเกิดเหตุการณ์ทั้งระบบ ฉันมีเธรดในแอปพลิเคชันที่รอเหตุการณ์ที่มีชื่อโกลบอลและทำงานเมื่อมีการตั้งค่าเหตุการณ์นั้น ในอีกด้านหนึ่งแอปพลิเคชันของฉันอาจต้องหยุดก่อนที่เหตุการณ์จะเกิดขึ้นโดยต้องปิดเธรดที่รอนั้น ซามูไรในการเขียนโค้ดสิ่งนี้คืออะไร?
Corvin

@Corvin: คุณสามารถมีลูปที่รอ (ด้วยการหมดเวลาสั้น ๆ ) สำหรับเหตุการณ์จากนั้นตรวจสอบว่าควรหยุดพยายามรอหรือไม่ (เพื่อให้สามารถออกได้ตามปกติ) ด้วยวิธีนี้คุณสามารถส่งสัญญาณว่าเธรดควรหยุดและคุณควรรอนานเท่าที่หมดเวลาเท่านั้นจึงจะหยุดได้
Kevin Kibler

2
@Corvin ถ้าคุณทำให้เธรดที่รอนั้นเป็นเธรดพื้นหลังคุณไม่ควรต้องปิดก่อนที่แอปพลิเคชันจะหยุดทำงาน
Don Kirkby

17

ทำไมไม่อยู่เสมอ? ในกรณีใดบ้างที่จะไม่ยุติเธรด

สำหรับผู้เริ่มต้นเธรดอาจจับThreadAbortExceptionและยกเลิกการสิ้นสุดของตัวเอง หรืออาจทำการคำนวณที่ใช้เวลาตลอดไปในขณะที่คุณกำลังพยายามยกเลิก ด้วยเหตุนี้รันไทม์จึงไม่สามารถรับประกันได้ว่าเธรดจะจบลงหลังจากที่คุณขอไปเสมอ

ThreadAbortException มีมากขึ้น:

เมื่อมีการเรียกใช้เมธอด Abort เพื่อทำลายเธรดรันไทม์ภาษาทั่วไปจะพ่น ThreadAbortException ThreadAbortException เป็นข้อยกเว้นพิเศษที่สามารถจับได้ แต่จะถูกเพิ่มขึ้นอีกครั้งโดยอัตโนมัติเมื่อสิ้นสุดบล็อกการจับ เมื่อเกิดข้อยกเว้นนี้รันไทม์จะเรียกใช้บล็อกสุดท้ายทั้งหมดก่อนที่จะสิ้นสุดเธรด เนื่องจากเธรดสามารถทำการคำนวณแบบไม่มีขอบเขตในบล็อกสุดท้ายหรือเรียกร้องThread.ResetAbort()ให้ยกเลิกการยกเลิกจึงไม่มีการรับประกันว่าเธรดจะสิ้นสุดลง

คุณไม่จำเป็นต้องAbort()ร้อยด้ายด้วยตนเอง CLR จะทำงานสกปรกทั้งหมดให้คุณหากคุณปล่อยให้เมธอดในเธรดกลับมา ที่จะสิ้นสุดเธรดตามปกติ


ฉันจำเป็นต้องยกเลิก () มันเนื่องจากการวนรอบข้อความเริ่มต้นในเธรดนั้น (Dispatcher.Run ();) ถ้าฉันเข้าใจถูกต้องฉันต้องเรียกใช้เมธอดที่เรียกกลับเข้ามาในเธรดจึงจะเสร็จสิ้น?
user101375

7

FileStream.Read()เพื่อไปป์ที่มีชื่อที่อยู่ในขณะนี้ไม่ได้รับอะไร (บล็อคโทรอ่านในขณะที่รอข้อมูลขาเข้า) Thread.Abort()จะไม่ตอบสนองต่อการ มันยังคงอยู่ในการRead()โทร


6

จะเกิดอะไรขึ้นถ้าเธรดกำลังล็อคและถูกยกเลิก / ถูกฆ่า? ทรัพยากรยังคงติดขัด

ทำงานได้ดีเมื่อเมื่อเธรดการเรียกยกเลิกตัวเอง แต่ไม่ใช่เธรดอื่น ยกเลิกยกเลิกเธรดที่ได้รับผลกระทบอย่างมีประสิทธิภาพแม้ว่าจะยังไม่เสร็จสิ้นภารกิจและไม่ให้โอกาสในการล้างทรัพยากร

อ้างอิงMSDN


โปรดดู แนวทางปฏิบัติที่ดีที่สุดของ Managed Threading


5

ฉันไม่สามารถยกเลิกเธรดที่ติดอยู่ในลูปได้:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

อย่างไรก็ตามฉันสามารถยกเลิกเธรดได้หากสลีประหว่างลูป:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
สิ่งนี้ดูเหมือนจะไม่เป็นความจริงฉันรันโปรแกรมทดสอบ: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("aborting @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L


3

เนื่องจากคุณสามารถจับThreadAbortExceptionและโทรThread.ResetAbortภายในตัวจัดการได้


0

OT: สำหรับการใช้เวลาตลก ๆ ที่ครอบคลุมไม่เข้าใจภาษามีประโยชน์และน่าสงสัยเกี่ยวกับการเกิดพร้อมกันโปรดดูVerity Stob !


-1

ฉันเคยมีกรณีที่เธรดยุ่งเกินกว่าที่จะได้ยินการเรียก Abort () ซึ่งมักจะส่งผลให้ ThreadAbortingException ถูกส่งไปยังรหัสของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.