Tôi không quan tâm khi nào chính xác m_Done sẽ được đặt thành true. Câu hỏi của tôi là tôi có bảo đảm bằng đặc tả ngôn ngữ C# và thư viện Task song song mà cuối cùng m_Done sẽ đúng nếu tôi truy cập nó từ một luồng khác?
số
Các đọc của m_Done
là non-volatile và do đó có thể được di chuyển tùy ý xa về phía sau trong thời gian, và kết quả có thể được lưu trữ. Kết quả là, nó có thể được quan sát là false
trên mọi lần đọc cho mọi thời đại.
Tôi cần biết liệu mã hiện tại sẽ hoạt động tương tự nếu chạy trên x86, x64, Itanium hoặc ARM.
Không có sự đảm bảo nào được thực hiện bởi đặc tả rằng mã sẽ được quan sát để thực hiện tương tự trên các mô hình bộ nhớ mạnh (x86) và yếu (ARM).
Đặc điểm kỹ thuật khá rõ ràng về những gì đảm bảo được thực hiện về đọc và ghi không dễ bay hơi: chúng có thể được sắp xếp lại tùy ý trên các chủ đề khác nhau trong trường hợp không có các sự kiện đặc biệt nhất định như khóa.
Đọc thông số kỹ thuật để biết chi tiết, đặc biệt là chút về tác dụng phụ khi chúng liên quan đến truy cập dễ bay hơi. Nếu bạn có thêm câu hỏi sau đó, sau đó đăng câu hỏi mới. Đây là thứ rất phức tạp.
Ngoài ra câu hỏi giả định rằng bạn đang bỏ qua các cơ chế hiện có để xác định rằng một nhiệm vụ được hoàn thành, và thay vào đó là cuộn của riêng bạn. Các cơ chế hiện có được thiết kế bởi các chuyên gia; sử dụng chúng.
Tôi thấy rất nhiều mã được viết theo cách này (không có khóa hoặc dễ bay hơi) và tôi không chắc liệu mã đó có chính xác hay không.
Nó gần như chắc chắn là không.
Một bài tập tốt để gây ra cho người viết mã mà là thế này:
static volatile bool q = false;
static volatile bool r = false;
static volatile bool s = false;
static volatile bool t = false;
static object locker = new object();
static bool GetR() { return r; } // No lock!
static void SetR() { lock(locker) { r = true; } }
static void MethodOne()
{
q = true;
if (!GetR())
s = true;
}
static void MethodTwo()
{
SetR();
if (!q)
t = true;
}
Sau khi khởi tạo của các trường, MethodOne được gọi từ một thread, MethodTwo được gọi từ khác. Lưu ý rằng tất cả mọi thứ là dễ bay hơi và rằng ghi vào r không chỉ là dễ bay hơi, nhưng hoàn toàn có rào chắn. Cả hai phương pháp đều hoàn thành bình thường. Có thể sau đó cho s và t để bao giờ cả hai được quan sát là đúng trên thread đầu tiên? Có thể trên x86? Nó xuất hiện không; nếu chuỗi đầu tiên thắng cuộc đua thì t vẫn là false và nếu chuỗi thứ hai thắng thì s vẫn là false; phân tích này là sai. Tại sao? (Gợi ý: x86 được phép viết lại như thế nào MethodOne
?)
Nếu bộ mã hóa không thể trả lời câu hỏi này thì hầu như không thể lập trình chính xác với biến động và không được chia sẻ bộ nhớ trên các chủ đề không có khóa.
tôi không thể không cảm thấy rằng điểm của 'async'/'đang chờ đợi' là để tránh những câu hỏi khó này ... – Aron
@Aron Không, không phải vậy. Nếu mã của bạn sử dụng 'async'-'await' làm (hoặc có thể) chạy trên nhiều luồng, bạn vẫn cần phải đồng bộ hóa đúng cách. – svick
@svick Tùy thuộc. Bạn có thể sử dụng 'await' để đồng bộ hóa và sắp xếp kết quả cho chuỗi mà" sở hữu "đối tượng đó, và có THAT thiết lập thuộc tính. – Aron