ฉันเดาว่าเครื่องมือเพิ่มประสิทธิภาพถูกหลอกโดยไม่มีคีย์เวิร์ด 'ระเหย' ในisCompleteตัวแปร
แน่นอนคุณไม่สามารถเพิ่มได้เนื่องจากเป็นตัวแปรท้องถิ่น และแน่นอนว่าเนื่องจากเป็นตัวแปรในท้องถิ่นจึงไม่จำเป็นต้องใช้เลยเพราะคนในพื้นที่จะเก็บไว้ในกองและมักจะ "สด" อยู่เสมอ
อย่างไรก็ตามหลังจากรวบรวมมันเป็นไม่ได้เป็นตัวแปรท้องถิ่น เนื่องจากมีการเข้าถึงในผู้ร่วมประชุมที่ไม่ระบุชื่อรหัสจึงถูกแยกออกและถูกแปลเป็นคลาสผู้ช่วยเหลือและฟิลด์สมาชิกบางอย่างเช่น:
public static void Main(string[] args)
{
TheHelper hlp = new TheHelper();
var t = new Thread(hlp.Body);
t.Start();
Thread.Sleep(500);
hlp.isComplete = true;
t.Join();
Console.WriteLine("complete!");
}
private class TheHelper
{
public bool isComplete = false;
public void Body()
{
int i = 0;
while (!isComplete) i += 0;
}
}
ตอนนี้ฉันสามารถจินตนาการได้ว่าคอมไพเลอร์ / เครื่องมือเพิ่มประสิทธิภาพ JIT ในสภาพแวดล้อมแบบมัลติเธรดเมื่อTheHelperคลาสการประมวลผลสามารถแคชค่าfalseในรีจิสเตอร์หรือสแต็กเฟรมที่จุดเริ่มต้นของBody()เมธอดและไม่รีเฟรชจนกว่าเมธอดจะสิ้นสุด นั่นเป็นเพราะไม่มีการรับประกันว่าเธรด & เมธอดจะไม่สิ้นสุดก่อนที่ "= true" จะถูกเรียกใช้งานดังนั้นหากไม่มีการรับประกันทำไมไม่แคชและเพิ่มประสิทธิภาพในการอ่านฮีปอ็อบเจ็กต์เพียงครั้งเดียวแทนที่จะอ่านในทุกๆ การทำซ้ำ
นี่คือเหตุผลว่าทำไมคำหลักจึงvolatileมีอยู่
เพื่อให้คลาสตัวช่วยนี้แก้ไขได้ ดีขึ้นเล็กน้อย 1)ในสภาพแวดล้อมแบบมัลติเธรดควรมี:
public volatile bool isComplete = false;
แต่แน่นอนเนื่องจากเป็นโค้ดที่สร้างขึ้นโดยอัตโนมัติคุณจึงไม่สามารถเพิ่มได้ แนวทางที่ดีกว่าคือการเพิ่มlock()s รอบ ๆ การอ่านและการเขียนisCompletedหรือการใช้ยูทิลิตี้การซิงโครไนซ์หรือเธรด / การทำเธรดที่พร้อมใช้งานอื่น ๆ แทนที่จะพยายามทำแบบโลหะเปล่า (ซึ่งจะไม่เป็นโลหะเปล่า เนื่องจากเป็น C # บน CLR กับ GC, JIT และ (.. ))
ความแตกต่างในโหมดดีบักอาจเกิดขึ้นเนื่องจากในโหมดดีบักการเพิ่มประสิทธิภาพจำนวนมากถูกยกเว้นดังนั้นคุณสามารถดีบักโค้ดที่คุณเห็นบนหน้าจอได้ ดังนั้นจึงwhile (!isComplete)ไม่ได้รับการปรับให้เหมาะสมเพื่อให้คุณสามารถตั้งค่าเบรกพอยต์ได้ที่นั่นดังนั้นจึงisCompleteไม่ถูกแคชในรีจิสเตอร์หรือสแต็กอย่างจริงจังเมื่อเมธอดเริ่มต้นและอ่านจากอ็อบเจ็กต์บนฮีปในทุกๆการวนซ้ำ
BTW. นั่นเป็นเพียงการคาดเดาของฉัน ฉันไม่ได้พยายามรวบรวมมันด้วยซ้ำ
BTW. ดูเหมือนจะไม่ใช่ข้อผิดพลาด มันเหมือนกับผลข้างเคียงที่คลุมเครือมากกว่า นอกจากนี้ถ้าฉันพูดถูกก็อาจเป็นความบกพร่องทางภาษา - C # ควรอนุญาตให้วางคีย์เวิร์ด 'ระเหย' ในตัวแปรท้องถิ่นที่จับและเลื่อนระดับเป็นฟิลด์สมาชิกในการปิด
1)ดูด้านล่างสำหรับความคิดเห็นจาก Eric Lippert เกี่ยวกับvolatileและ / หรือบทความที่น่าสนใจนี้ซึ่งแสดงระดับความซับซ้อนที่เกี่ยวข้องในการตรวจสอบให้แน่ใจว่ารหัสที่อาศัยอยู่volatileนั้นปลอดภัย .. เอ่อดี .. เอ่อเอาเป็นว่าตกลง