Đầu tiên - hầu hết các lớp sẽ không bao giờ cần phải an toàn cho luồng. Sử dụng YAGNI : chỉ áp dụng an toàn luồng khi bạn biết bạn thực sự sẽ sử dụng nó (và kiểm tra nó).
Đối với công cụ cấp phương thức, có [MethodImpl]
:
[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}
Điều này cũng có thể được sử dụng trên các phụ kiện (thuộc tính và sự kiện):
private int i;
public int SomeProperty
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return i; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { i = value; }
}
Lưu ý rằng các sự kiện giống như trường được đồng bộ hóa theo mặc định, trong khi các thuộc tính được triển khai tự động thì không :
public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized
Cá nhân, tôi không thích việc thực hiện MethodImpl
vì nó khóa this
hoặc typeof(Foo)
- điều này trái với thực tiễn tốt nhất. Tùy chọn ưa thích là sử dụng ổ khóa của riêng bạn:
private readonly object syncLock = new object();
public void SomeMethod() {
lock(syncLock) { /* code */ }
}
Lưu ý rằng đối với các sự kiện giống như trường, việc thực hiện khóa phụ thuộc vào trình biên dịch; trong các trình biên dịch cũ của Microsoft, nó là lock(this)
/ lock(Type)
- tuy nhiên, trong các trình biên dịch gần đây hơn, nó sử dụng cácInterlocked
bản cập nhật - vì vậy an toàn cho luồng mà không có các phần khó chịu.
Điều này cho phép sử dụng chi tiết hơn và cho phép sử dụng Monitor.Wait
/ Monitor.Pulse
etc để giao tiếp giữa các luồng.
Một mục blog liên quan (sau này xem lại ).