Tệ nhất (sẽ không thực sự hoạt động)
Thay đổi modifier tiếp cận của counter
đểpublic volatile
Như những người khác đã đề cập, điều này tự nó không thực sự an toàn. Điểm chính volatile
là nhiều luồng chạy trên nhiều CPU có thể và sẽ lưu trữ dữ liệu và hướng dẫn lại thứ tự.
Nếu không volatile
, và CPU A tăng một giá trị, thì CPU B có thể không thực sự thấy giá trị tăng đó cho đến một lúc sau, điều này có thể gây ra sự cố.
Nếu có volatile
, điều này chỉ đảm bảo hai CPU nhìn thấy cùng một dữ liệu cùng một lúc. Điều đó hoàn toàn không ngăn cản họ xen kẽ các hoạt động đọc và ghi của họ, đây là vấn đề bạn đang cố gắng tránh.
Tốt thứ hai:
lock(this.locker) this.counter++
;
Điều này là an toàn để làm (miễn là bạn nhớ đến lock
mọi nơi khác mà bạn truy cập this.counter
). Nó ngăn chặn bất kỳ luồng nào khác thực thi bất kỳ mã nào khác được bảo vệ bởi locker
. Cũng sử dụng khóa, ngăn chặn các vấn đề sắp xếp lại đa CPU như trên, điều này thật tuyệt vời.
Vấn đề là, khóa rất chậm và nếu bạn sử dụng lại locker
ở một nơi khác không thực sự liên quan thì cuối cùng bạn có thể chặn các luồng khác mà không có lý do.
Tốt
Interlocked.Increment(ref this.counter);
Điều này là an toàn, vì nó thực sự đọc, tăng và viết trong 'một lần nhấn' mà không thể bị gián đoạn. Vì điều này, nó sẽ không ảnh hưởng đến bất kỳ mã nào khác và bạn cũng không cần phải nhớ khóa ở nơi khác. Nó cũng rất nhanh (như MSDN nói, trên các CPU hiện đại, đây thường chỉ là một lệnh CPU).
Tuy nhiên, tôi không hoàn toàn chắc chắn nếu nó xoay quanh các CPU khác sắp xếp lại mọi thứ hoặc nếu bạn cũng cần kết hợp dễ bay hơi với mức tăng.
Liên khóa:
- CÁC PHƯƠNG PHÁP GIẢI QUYẾT ĐƯỢC AN TOÀN AN TOÀN TRÊN MỌI SỐ L CORI HOẶC CPU.
- Các phương thức lồng vào nhau áp dụng một hàng rào đầy đủ xung quanh các hướng dẫn mà chúng thực hiện, do đó việc sắp xếp lại không xảy ra.
- Các phương thức lồng vào nhau không cần hoặc thậm chí không hỗ trợ truy cập vào trường dễ bay hơi , vì dễ bay hơi được đặt một nửa hàng rào xung quanh các hoạt động trên trường đã cho và lồng vào nhau là sử dụng toàn bộ hàng rào.
Lưu ý: Những gì dễ bay hơi thực sự tốt cho.
Vì volatile
không ngăn được các loại vấn đề đa luồng này, nó dùng để làm gì? Một ví dụ điển hình là bạn có hai luồng, một luồng luôn ghi vào một biến (nói queueLength
) và một luồng luôn đọc từ cùng một biến đó.
Nếu queueLength
không dễ bay hơi, luồng A có thể viết năm lần, nhưng luồng B có thể thấy những lần ghi đó bị trì hoãn (hoặc thậm chí có khả năng sai thứ tự).
Một giải pháp sẽ là khóa, nhưng bạn cũng có thể sử dụng dễ bay hơi trong tình huống này. Điều này sẽ đảm bảo rằng chủ đề B sẽ luôn nhìn thấy điều cập nhật nhất mà chủ đề A đã viết. Tuy nhiên, lưu ý rằng logic này chỉ hoạt động nếu bạn có nhà văn không bao giờ đọc và độc giả không bao giờ viết và nếu điều bạn đang viết là một giá trị nguyên tử. Ngay sau khi bạn thực hiện một lần đọc-sửa đổi-ghi, bạn cần chuyển đến các hoạt động lồng vào nhau hoặc sử dụng Khóa.