คาดว่า ThreadAbort สำหรับเธรดพื้นหลัง

ฉันมีสิ่งต่อไปนี้

public static Thread testThread = new Thread(ThreadStart) {Name = "TestThread", IsBackground = true};
private void Form_Load()
{
    testThread.Start()
}
private static void ThreadStart()
{
    int count = 0;
    try
    {
        while (true)
        {
            count++;
        }
    }
    catch (Exception ex)
    {

        StreamWriter stream = new StreamWriter(File.OpenWrite("Exception.txt"));
        stream.WriteLine(count + "\n" + ex);
        stream.Flush();
        stream.Close();
    }
}

เมื่อฉันโทร Thread.Abort() ฉันพบข้อยกเว้นและเขียนลงในไฟล์ อย่างไรก็ตาม ถ้าฉันปิดแอปพลิเคชันแทน ไม่มีอะไรเขียนเลย ฉันยังมี

AppDomain.CurrentDomain.UnhandledException +=
   new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Application.ThreadException +=
   new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

แต่ดูเหมือนว่าจะไม่มีข้อยกเว้นเกิดขึ้น

ฉันคิดว่าการเพิ่มคำถามเป็นเรื่องที่รอบคอบ

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


person galford13x    schedule 05.02.2012    source แหล่งที่มา
comment
เริ่มกระทู้ยังไงคะ? ทำไมคุณถึงคาดหวังว่า ThreadAbort จะถูกโยนทิ้ง? และคำถามคืออะไร?   -  person Chris Shain    schedule 06.02.2012
comment
จากการอ่านทั้งหมดของฉัน เมื่อแอปพลิเคชันออก เธรดพื้นหลังทั้งหมดที่ทำงานอยู่จะถูกยกเลิกผ่าน ThreadAbortException ฉันเริ่มเธรดโดยใช้ Thread.Start(ThreadStart)   -  person galford13x    schedule 06.02.2012
comment
@Chris: นี่คือที่ที่ฉันได้รับข้อมูลบางส่วนของฉัน stackoverflow.com/questions/1354196/   -  person galford13x    schedule 06.02.2012
comment
ทำไมคุณถึงใช้ Thread.Abort() กระทู้ฆ่ามันไม่ดีใช่ไหม? โน้มน้าวพวกเขาให้ฆ่าตัวตายดีกว่า จะได้ไม่ต้องติดคุก   -  person CodesInChaos    schedule 06.02.2012
comment
@CodeInChaos: มันเป็นแบบฝึกหัดด้านการศึกษา แต่คำถามสำหรับคุณคือ คุณจะพิจารณาสร้างเธรดเป็นเธรดพื้นหลังแล้วออกจากการฆาตกรรมแอปพลิเคชันหรือไม่ ฉันเคยเห็นสิ่งนี้เกิดขึ้นในตัวอย่างและห้องสมุดหลายแห่ง และสงสัยอยู่เสมอว่าทำไมพวกเขาจึงไม่ใช้รูปแบบที่แตกต่างกันเพื่อแก้ไขปัญหาการจบกระทู้อย่างสง่างามยิ่งขึ้น นั่นคือเหตุผลที่ฉันถามคำถามตอนนี้   -  person galford13x    schedule 06.02.2012


คำตอบ (3)


ก่อนอื่น แอปพลิเคชันอาจจะไม่ออก เนื่องจากคุณไม่ได้ทำให้สิ่งเหล่านี้กลายเป็นเธรดพื้นหลัง ฉันเดาว่าตัวจัดการงานจะแสดงสำเนา EXE ของคุณที่ทำงานโดยไม่คาดคิด คุณต้องตั้งค่า Thread.IsBackground ให้เป็นจริงบนวัตถุเธรดก่อนที่จะเรียก Start

ประการที่สอง ลักษณะการทำงานที่คุณคาดหวังจะถูก debunked อย่างชัดเจนโดย เอกสารประกอบ:

บันทึก

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

แก้ไข:

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

person Chris Shain    schedule 05.02.2012
comment
ทำไมมันไม่เป็นกระทู้พื้นหลัง ฉันกำลังตั้งค่าคุณสมบัติ IsBackground = true เมื่อฉันเริ่มต้นเธรด ฉันจะตรวจสอบอีกครั้งว่านี่เป็นเรื่องจริงในขณะนี้ - person galford13x; 06.02.2012
comment
ฉันได้ตรวจสอบซ้ำแล้วซ้ำอีกขณะทำการดีบัก และ IsBackground สำหรับ testThread นั้นเป็นจริง - person galford13x; 06.02.2012
comment
ในกรณีดังกล่าว โปรดดูเอกสารที่ฉันกล่าวถึงข้างต้น MSDN ชนะความคิดเห็นของผู้ชายบางคนเกี่ยวกับสแต็กล้น 99999 ครั้งจาก 100,000 ครั้ง - person Chris Shain; 06.02.2012
comment
จุดประสงค์ของฉันคือเพื่อการศึกษาในการทำความเข้าใจความแตกต่างระหว่างเธรดพื้นหลังและเบื้องหน้า ฉันเคยใช้ไลบรารี่ในอดีตที่ต้องอาศัยเธรดพื้นหลังเพื่อออกผ่านการออกจากแอปพลิเคชัน สำหรับทรัพยากรที่ปล่อยออกมาเมื่อแอปพลิเคชันออก สิ่งนี้ไม่เป็นความจริงทั้งหมด ฉันมีแอปพลิเคชั่นที่เปิดไฟล์ แต่ออกจากระบบระงับการล็อคไฟล์ก่อนกำหนดแม้ว่าจะไม่มีกระบวนการใดแสดงอยู่ใน TaskManager ก็ตาม วิธีเดียวที่จะปลดล็อคได้คือใช้เครื่องมือเฉพาะหรือรีบูตระบบ - person galford13x; 06.02.2012
comment
AFAIK ที่ไม่สามารถทำได้ใน Windows อาจจะผิดก็ได้ แน่นอนว่าเป็นไปไม่ได้ที่จะใช้โครงสร้าง .NET I/O สิ่งเดียวที่พิเศษเกี่ยวกับเธรดพื้นหลังใน .NET ก็คือ เธรดเหล่านี้จะไม่ทำให้กระบวนการทำงานต่อไป - person Chris Shain; 06.02.2012
comment
จุดดี ฉันเข้าใจผิดบางโพสต์ใน stackoeverflow ก่อนหน้า เนื่องจากมีคำพูดจาก MSDN ด้วย หลังจากอ่านซ้ำ ฉันพบว่าไม่เห็นว่ามีข้อยกเว้นเกิดขึ้นเพื่อหยุดเธรด มีเพียงเธรดเท่านั้นที่ถูกหยุด ไม่ได้ระบุว่าวิธีนี้ทำอย่างไร - person galford13x; 06.02.2012
comment
ฉันมีโปรแกรมล็อคไฟล์ใน windows แม้ว่าจะออกแล้วก็ตาม แม้ว่าฉันอาจไม่เห็นกระบวนการที่แสดงอยู่ในตัวจัดการงาน แต่อาจเป็นกระบวนการโกง/ย่อยที่เริ่มต้นขึ้น และฉันไม่รู้ว่าจะต้องค้นหาอะไร ใช้บางอย่างเช่น technet.microsoft.com/en-us/sysinternals/bb896653.aspx สามารถช่วยให้คุณค้นหาผู้กระทำผิดและปลดปล่อยทรัพยากรได้ - person galford13x; 06.02.2012
comment
การอ้างอิงถึงเอกสาร MSDN ของคุณใกล้เคียงกับสิ่งที่ฉันกำลังมองหามากที่สุด อย่างไรก็ตาม ฉันต้องการทราบว่า CLR ปิดระบบสำเร็จได้อย่างไร การรู้ว่าฉันไม่สามารถตรวจจับการปิดพื้นหลังได้นั้นค่อนข้างมีประโยชน์ ขอบคุณสำหรับความช่วยเหลือของคุณ - person galford13x; 06.02.2012
comment
อาจต้องการดูบทความนี้เกี่ยวกับการโฮสต์ CLR: msdn.microsoft com/en-us/magazine/cc163567.aspx#S3. ไม่ได้มีรายละเอียดมากนัก แต่ควรชี้ให้คุณไปในทิศทางที่ถูกต้อง - person Chris Shain; 06.02.2012
comment
ขอบคุณคริส ฉันจะลองดู - person galford13x; 06.02.2012

เมื่อ CLR ปิดกระบวนการ จะไม่เรียก Thread.Abort หรือสิ่งที่คล้ายกัน วิธีการเธรดของคุณจะไม่ออกเหมือนวิธีการหลักของคุณ

  1. สิ่งแรกที่ทำเมื่อคุณออกจากวิธีการหลักหรือเรียก Environment.Exit คือการสิ้นสุดออบเจ็กต์ทั้งหมดด้วยการหมดเวลา (เป็น 2 วินาทีใน .NET 2.0) จากนั้นแอปพลิเคชันจะยังคงยุติแอปพลิเคชันต่อไปโดยไม่คำนึงถึงตัวสรุปที่ค้างอยู่ในปัจจุบัน
  2. ถัดไปเรียกว่า Critical Finalizers
  3. จากนั้นเธรดทั้งหมดจะถูกระงับเพื่อไม่ให้เกิดความเสียหายในขณะที่ CLR กำลังปิดตัวลง
  4. แอปพลิเคชันของคุณออกแล้ว
person Alois Kraus    schedule 05.02.2012

หากคุณสมบัติ IsBackground ของเธรดของคุณคือ false จากนั้นเธรดของคุณก็จะยังคงอยู่ แม้ว่าหน้าต่างหลักของแอปพลิเคชันของคุณจะปิดไปแล้วก็ตาม

วิธีที่ดีที่สุดในการควบคุมอายุการใช้งานของเธรดในพื้นหลังคือการสร้าง รักษาการ ซึ่งโดยทั่วไปจะใช้เป็นฟิลด์ volatile bool ซึ่งโค้ดภายในเธรดจะตรวจสอบตามช่วงเวลาปกติ (เช่น ทุกครั้งที่วนซ้ำ) เธรดควรหยุดดำเนินการเมื่อ Sentinel บ่งชี้ว่าแอปพลิเคชันกำลังยุติ

รหัสต่อไปนี้แสดงการใช้ Sentinel เพื่อยุติเธรดหลังจาก 200 มิลลิวินาที:

public static Thread testThread = new Thread(ThreadStart) 
{
    Name = "TestThread", 
    IsBackground = false    // Allow thread to terminate naturally
};

private static volatile bool isTerminating = false;   // Sentinel

private void Form_Load()
{
    testThread.Start();
    Thread.Sleep(200);      // Sleep 200 milliseconds
    isTerminating = true;   // Set sentinel to terminate thread
}

private static void ThreadStart()
{
    int count = 0;

    while (!isTerminating)   // Keep looping until sentinel is set
        count++;

    using (StreamWriter stream = new StreamWriter(File.OpenWrite("Result.txt")))
    {
        stream.WriteLine(count);
        stream.Flush();
    }
}

แก้ไข: เพื่อตอบคำถามสุดท้ายของคุณ “จะจับ ThreadAbortException เพื่อล้างทรัพยากรที่อาจมีอยู่ในเธรดได้อย่างไร” คุณสามารถใช้บล็อก catch ธรรมดาได้ ThreadAbortException อาจถูกจับได้เหมือนกับข้อยกเว้นอื่นๆ แต่จะถูกยกขึ้นอีกครั้งโดยอัตโนมัติเมื่อสิ้นสุดบล็อก catch อย่างไรก็ตาม ดังที่ Chris กล่าวไว้ หากกระบวนการกำลังออก ThreadAbortException จะไม่เพิ่มขึ้นเลย

person Douglas    schedule 05.02.2012
comment
ดังที่แสดงไว้ว่าเป็นจริง โปรดสังเกตว่า new Thread(ThreadStart) {isBackground = true}; ฉันจะตรวจสอบอีกครั้งเพื่อดูว่าก่อนที่จะเริ่มเธรดมันเป็นเรื่องจริงหรือไม่ - person galford13x; 06.02.2012
comment
ฉันเข้าใจรูปแบบการประมวลผลเธรดทั่วไป แต่นี่มีวัตถุประสงค์เพื่อการศึกษาเพิ่มเติมในการทำความเข้าใจว่าจะเกิดอะไรขึ้นเมื่อเธรดพื้นหลังออก ฉันใช้ไลบรารี่ที่แทนที่จะใช้รูปแบบเธรดที่ดี พวกเขาใช้เธรด IsBackground เพื่อออกจากเธรด - person galford13x; 06.02.2012