11 Chủ đề trong C # - Phần 11: ReaderWriterLock

(Post 13/11/2007) Thông thường, các trường hợp của một kiểu an toàn cho các thao tác đọc đồng thời, nhưng không an toàn cho các cập nhật đồng thời (cũng không phải đọc và cập nhật đồng thời). Điều này cũng có thể đúng với các tài nguyên như tệp. Mặc dù việc bảo vệ các trường hợp của các loại như vậy bằng một khóa độc quyền đơn giản cho tất cả các chế độ truy cập thường là một mẹo nhỏ, nhưng nó có thể hạn chế đồng thời một cách bất hợp lý nếu có nhiều người đọc và chỉ cập nhật không thường xuyên. Một ví dụ về nơi điều này có thể xảy ra là trong máy chủ ứng dụng kinh doanh, nơi dữ liệu thường được sử dụng được lưu vào bộ nhớ đệm để truy xuất nhanh trong các trường tĩnh. Lớp ReaderWriterLock được thiết kế để cung cấp tính năng khóa khả dụng tối đa chỉ trong trường hợp này.

  • Phần 1: Tổng quan và khái niệm
  • Phần 2: Tạo và bắt đầu chủ đề
  • Phần 3: Cơ bản về đồng bộ hóa
  • Phần 4: Khóa và an toàn chỉ
  • Phần 5: Ngắt và hủy bỏ
  • Phần 6: Trạng thái luồng
  • Phần 7: Xử lý Chờ
  • Phần 8: Bối cảnh đồng bộ hóa
  • Phần 9: Căn hộ và Hình thức Windows
  • Phần 10: BackgroundWorker

ReaderWriterLock cung cấp các phương pháp riêng biệt để lấy các khóa đọc và ghi – AcquireReaderLock và AcquireWriterLock. Cả hai phương thức đều yêu cầu đối số timeout và sẽ ném ra một ApplicationException nếu thời gian chờ xảy ra (thay vì trả về false, giống như hầu hết các phương thức tương đương trong các lớp luồng). Thời gian chờ có thể xảy ra khá dễ dàng nếu tài nguyên bị cạnh tranh nhiều.

Khóa được giải phóng bằng cách gọi ReleaseReaderLock hoặc ReleaseWriterLock. Các phương thức này tôn trọng khóa lồng nhau; một phương thức ReleaseLock cũng được cung cấp để xóa tất cả các cấp độ lồng khóa trong một lần truy cập. (Sau đó, người ta có thể gọi RestoreLock để khóa lại về cùng mức trước khi gọi ReleaseLock – để bắt chước hành vi chuyển đổi khóa của Monitor.Wait).

Người ta có thể bắt đầu với khóa đọc bằng cách gọi AcquireReaderLock sau đó nâng cấp lên khóa ghi bằng cách gọi UpgradeToWriterLock . Phương thức trả về một cookie sau đó có thể được sử dụng để gọi DowngradeFromWriterLock . Hệ thống này cho phép người đọc tạm thời yêu cầu quyền ghi trong khi không phải xếp hàng lại sau khi bị giáng chức.

Trong ví dụ sau, bốn luồng được bắt đầu – một luồng liên tục thêm các mục vào danh sách; một liên tục xóa các mục khỏi danh sách và hai liên tục báo cáo số lượng các mục trong danh sách. Hai cái trước có được khóa ghi; hai cái sau có được khóa đọc. Thời gian chờ 10 giây được sử dụng cho mỗi khóa (các trình xử lý ngoại lệ thường được bao gồm để bắt ApplicationException kết quả ; trong ví dụ này, chúng được bỏ qua cho ngắn gọn).

class Program {
static ReaderWriterLock rw = new ReaderWriterLock ();
danh sách tĩnh items = danh sách mới ();
static Random rand = new Random ();

static void Main (string [] args) {
new Thread (Delegate () {while (true) AppendItem ();}) .Start ();
new Thread (Delegate () {while (true) RemoveItem ();}) .Start ();
new Thread (Delegate () {while (true) WriteTotal ();}) .Start ();
new Thread (Delegate () {while (true) WriteTotal ();}) .Start ();
}

static int GetRandNum (int max) {lock (rand) return rand.Next (max); }

static void WriteTotal () {
rw.AcquireReaderLock (10000);
int tot = 0; foreach (int i trong các mục) tot + = i;
Console.WriteLine (tot);
rw.ReleaseReaderLock ();
}

static void AppendItem () {
rw.AcquireWriterLock (10000);
items.Add (GetRandNum (1000));
Thread.SpinWait (400);
rw.ReleaseWriterLock ();
}

static void RemoveItem () {
rw.AcquireWriterLock (10000);
if (items.Count> 0)
items.RemoveAt (GetRandNum (items.Count));
rw.ReleaseWriterLock ();
}
}

Bởi vì thêm một mục vào Danh sách nhanh hơn là xóa nó, ví dụ này bao gồm một SpinWait trong phương thức AppendItem để giúp mọi thứ đồng đều – giữ cho tổng số mục không bị chạy mất.

(Sưu tầm)

FPT Aptech trực thuộc Tổ chức Giáo dục FPT có hơn 25 năm kinh nghiệm đào tạo lập trình viên quốc tế tại Việt Nam, và luôn là sự lựa chọn ưu tiên của các sinh viên và nhà tuyển dụng.
0981578920
icons8-exercise-96