2011-01-26 24 views
6

Đây là lần theo dõi previous question về khóa trên hai đối tượng Danh sách (T). Câu trả lời có ích nhưng để lại cho tôi một câu hỏi khác.Cách thích hợp để sử dụng SyncLock (nói chung)

Giả sử tôi có một chức năng như thế này:

Public Function ListWork() As Integer 
    List1.Clear() 
    ..Some other work which does not modify List1.. 
    List1.AddRange(SomeArray) 
    ..Some more work that does not involve List1.. 
    Retrun List1.Count 
End Function 

mà nằm trong một lớp học mà tuyên bố List1. Trong một môi trường đa luồng, bây giờ tôi hiểu rằng tôi nên có một đối tượng khóa riêng cho List1 và khóa List1 bất cứ khi nào nó được sửa đổi hoặc liệt kê. Câu hỏi của tôi là, tôi nên làm điều này:

Private List1Lock As New Object 
Public Function ListWork() As Integer 
    SyncLock List1Lock 
    List1.Clear() 
    End SyncLock 
    ..Some other work which does not modify List1.. 
    SyncLock List1Lock 
    List1.AddRange(SomeArray) 
    End SyncLock 
    ..Some more work that does not involve List1.. 
    SyncLock List1Lock 
    Dim list1Count As Integer = List1.Count 
    End SyncLock 
    Retrun list1Count 
End Function 

hay này:

Private List1Lock As New Object 
Public Function ListWork() As Integer 
    SyncLock List1Lock 
    List1.Clear() 
    ..Some other work which does not modify List1.. 
    List1.AddRange(SomeArray) 
    ..Some more work that does not involve List1.. 
    Dim list1Count As Integer = List1.Count 
    End SyncLock 
    Retrun list1Count 
End Function 

Tôi đoán rằng ví dụ trước đây là tối ưu?

Trả lời

9

Từ các ví dụ, thật khó để biết cái nào là đúng, nếu có. Một vài nguyên tắc/quan sát mặc dù có thể giúp bạn trả lời câu hỏi của bạn hoặc biết những gì cần cung cấp để biết thêm thông tin:

Trước tiên, bạn có phải đồng bộ hóa không? Nó sẽ có ý nghĩa hơn cho mỗi thread để có một thể hiện của lớp này? Nếu mỗi cá thể là địa phương cho chuỗi, và chỉ được sửa đổi và sử dụng trên chuỗi đó, bạn không cần khóa.

Nếu mục đích của lớp này và sử dụng luồng là để xử lý song song một tập dữ liệu lớn hơn, có thể có ý nghĩa hơn cho luồng chính chia nhiệm vụ theo một cách hợp lý, và sau đó đợi chuỗi công việc hoàn thành. Trong trường hợp này, thay vì quản lý các chủ đề của riêng bạn, hãy nhìn vào ThreadPool và chờ xử lý. Hầu hết các công việc bẩn được thực hiện cho bạn sau đó.

Giới thiệu về đồng bộ hóa/khóa nói chung: Nếu hoạt động của bạn bị gián đoạn giữa các bước, liệu dữ liệu có nhất quán/hợp lệ không?

Trong ví dụ của bạn, giả sử bạn có hai chuỗi. Vị trí đầu tiên nằm trong khu vực giữa .AddRange().Count, khi chuỗi thứ hai xuất hiện cùng với chức năng và lấy khóa trên danh sách.

Chủ đề 1 chạy thêm một chút và nhấn khóa bảo vệ phương thức .Count và chuyển sang chế độ ngủ. Thread 2 trong khi chờ đợi xóa danh sách và sau đó phát hành khóa của nó, đánh thức Thread 1 lên, sau đó mua lại khóa.

Trong trường hợp này, Chủ đề 1 sẽ có 0 được trả lại từ hàm này, khi công việc được thực hiện theo chuỗi 1 để tạo danh sách.Và sau đó, độ dài danh sách sẽ không thực sự là 0, vì chuỗi 2 đã xuất hiện và điền vào danh sách.

Trong trường hợp này, các khóa xung quanh các hoạt động danh sách riêng lẻ sẽ phá vỡ chương trình, do đó, có ý nghĩa hơn khi có một khóa xung quanh giữa Clear và cuộc gọi Count.

Trong ngắn hạn, đa luồng là một cách hay để giới thiệu một lớp toàn bộ các lỗi tinh vi liên quan đến Race Conditions, thường dẫn đến Heisenbugs.

Bạn nên tránh các chủ đề khi có thể. Nếu bạn không thể, hãy cố gắng sắp xếp khối lượng công việc theo những cách yêu cầu đồng bộ hóa tối thiểu (ví dụ: cho luồng một tập hợp dữ liệu lúc bắt đầu, sau đó đợi cho nó hoàn thành tín hiệu, chẳng hạn như ví dụ về nhóm luồng được liên kết). Nếu bạn không thể làm điều đó, hãy cẩn thận, và luôn tự hỏi "Điều gì sẽ xảy ra nếu hai luồng chạy trong khu vực này".

Hy vọng điều này sẽ giúp bạn mang đến cho bạn những cuộc phiêu lưu trong tương lai bằng mã đa luồng.

+0

Tôi nghĩ rằng tôi đã hiểu điều này ngay bây giờ. Khá tinh tế. Tôi nên tham gia một lớp học hoặc một cái gì đó ... Cảm ơn sự thấu hiểu. –

6

"Nó phụ thuộc". Hai ví dụ có ngữ nghĩa khác nhau.

Trong ví dụ sau, toàn bộ các hoạt động là nguyên tử đối với khóa. Mặc dù trong ví dụ trước, quyền truy cập vào danh sách được bảo vệ trong khóa nhưng toàn bộ các hoạt động không thể (chính xác) được xem là nguyên tử (đối với khóa).

Hãy tưởng tượng điều gì sẽ xảy ra nếu hoạt động/luồng xen kẽ nếu ListWork được gọi trên cùng một đối tượng theo các chủ đề khác nhau.

Mã hóa vui vẻ.

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