2013-01-21 39 views
9

Tôi nghĩ rằng hầu hết mọi người nhận thức được những vấn đề sau đây sẽ xảy ra khi xây dựng trong chế độ Release (mã lấy từ Threading in C#):dễ bay hơi weirdness

static void Main() 
{ 
    bool complete = false; 

    var t = new Thread (() => 
    { 
    bool toggle = false; 
    while (!complete) toggle = !toggle; 
    }); 

    t.Start(); 
    Thread.Sleep (1000); 

    complete = true; 
    t.Join();  // Blocks indefinitely 
} 

do tối ưu hóa trình biên dịch bộ nhớ đệm giá trị của complete và do đó ngăn ngừa trẻ chuỗi từ bao giờ nhìn thấy giá trị được cập nhật.

Tuy nhiên, thay đổi mã trên một chút:

class Wrapper 
{ 
    public bool Complete { get; set; } 
} 

class Test 
{ 
    Wrapper wrapper = new Wrapper(); 

    static void Main() 
    { 
     var test = new Test(); 
     var t = new Thread(() => 
     { 
      bool toggle = false; 
      while (!test.wrapper.Complete) toggle = !toggle; 
     }); 

     t.Start(); 
     Thread.Sleep(1000); 

     test.wrapper.Complete = true; 
     t.Join();  // Blocks indefinitely 
    } 
} 

làm cho vấn đề đi xa (tức là sợi con có thể thoát khỏi sau 1 giây) mà không cần dùng volatile, hàng rào bộ nhớ, hoặc bất kỳ khác cơ chế giới thiệu một hàng rào ngầm.

Cách đóng gói bổ sung của cờ hoàn thành ảnh hưởng đến khả năng hiển thị giữa các chuỗi?

+1

Mã của bạn không được bảo đảm để hoạt động, nhưng cũng không đảm bảo không thành công. Bạn không nên dựa vào tối ưu hóa trình biên dịch cho tính chính xác (hoặc không chính xác trong trường hợp này). – svick

+1

@svick: Tôi không thực sự. Nó chỉ là một cái gì đó tôi nhận thấy vô tình. – Tudor

+1

bản sao có thể có của [Ví dụ tái tạo về việc sử dụng dễ bay hơi] (http://stackoverflow.com/questions/6164466/a-reproducable-example-of-volatile-usage) –

Trả lời

6

Tôi nghĩ rằng bạn có câu trả lời trong câu hỏi của bạn:

do biên dịch tối ưu hóa bộ nhớ đệm giá trị đầy đủ và do đó ngăn ngừa các chủ đề trẻ em từ bao giờ nhìn thấy những giá trị được cập nhật.

Tối ưu hóa trình biên dịch/JIT được thực hiện bất cứ khi nào có ý nghĩa/được coi là an toàn và hợp lý để triển khai. Vì vậy, bạn đã tìm thấy trường hợp khi tối ưu hóa không được thực hiện theo cách bạn mong đợi xảy ra - có thể có lý do chính đáng (ai đó phát hiện mẫu sử dụng này và tối ưu hóa khối) hoặc nó chỉ xảy ra không được tối ưu hóa (rất có thể).

+5

Điểm mấu chốt là đây là hành vi không xác định. Nhóm biên dịch có thể quyết định vào ngày mai để tối ưu hóa các thuộc tính giống như ví dụ đầu tiên, hoặc chúng không thể tối ưu hóa các thuộc tính đầu tiên (hoặc làm như vậy khác đi) sao cho nó không dừng lại. – Servy

+0

Tôi đồng ý với quan điểm của bạn và rất có thể đây là trường hợp. Tôi chỉ cố gắng tìm hiểu xem có một mẫu mà tôi có thể phát hiện khi xác định xem mã như thế này có bị lỗi hay không. – Tudor

0

Trường hợp đầu tiên là tuyên truyền bí danh đơn giản trên biến cục bộ. Các trình biên dịch thực hiện điều đó khá tích cực (http://en.m.wikipedia.org/wiki/Aliasing_(computing)) Trường hợp thứ hai, ngay cả khi nó trông giống nhau do sự tương đồng về các thuộc tính với các biến thành viên, có các lời gọi phương thức (getter/setter) và không thể đơn giản hóa được.

+0

trong trường hợp đầu tiên, nó không phải là một thiết lập đơn giản của giá trị .. runtime không thể chỉ "bỏ qua" một cái gì đó như thế –

+0

không nhận được những gì bạn có nghĩa là "không phải là một thiết lập đơn giản của giá trị". Tuyên truyền bí danh là một kỹ thuật biên dịch để đơn giản hóa hoặc thay thế các biến http://en.wikipedia.org/wiki/Aliasing_(computing) – nakhli

Các vấn đề liên quan