2013-06-07 38 views
6

Tôi có nhiều hàng đợi đang được truy cập bởi nhiều luồng. Để đạt được an toàn luồng, tôi đã làm như sau:Tôi có thể sử dụng các phần tử từ điển làm đối tượng khóa không?

private static Dictionary<string, Queue<string>> MyQueues = new Dictionary<string, Queue<string>>(); 

public static string GetNextQueueElementForKey(string key) 
{ 
    string res = string.Empty; 

    if (MyQueues.Keys.Contains(key)) 
    { 
     Queue<string> queue = MyQueues[key]; 
     lock (queue) 
     { 
      if (queue.Count() > 0) 
      { 
       res = queue.Dequeue(); 
      } 
     } 
    } 

    return res; 
} 

Tôi cũng có thể khóa MyQueues, nhưng sau đó tôi sẽ khóa nhiều hơn mức cần thiết. Vì vậy, câu hỏi của tôi là, nếu khóa một đối tượng chứa trong từ điển sẽ hoạt động - giả sử rằng giá trị của một khóa (hàng đợi) không bao giờ thay đổi.

+0

Câu hỏi của bạn đọc giống như một tuyên bố. Câu hỏi của bạn là gì? –

+0

Bạn không khóa các đối tượng, bạn khóa * tham chiếu đến các đối tượng *. Nói cách khác, liệu giá trị của vật thể có thay đổi không ảnh hưởng đến khóa. – Nolonar

+0

@Nolonar no, bạn tự khóa chính mình. Bạn có thể có 17 tài liệu tham khảo cho cùng một đối tượng - tất cả chúng sẽ khóa cùng một thứ. –

Trả lời

6

Bạn có thể - nhưng tôi thường sẽ không. Cá nhân tôi thường cố gắng để khóa trên đồng bằng System.Object trường hợp mà không được sử dụng cho bất cứ điều gì khác, và lý tưởng thậm chí không tiếp xúc với bất kỳ mã nào khác ngoài lớp khóa trên chúng. Bằng cách đó bạn có thể hoàn toàn chắc chắn rằng không có gì khác sẽ khóa.

Trong trường hợp này có vẻ như bạn đã có kiểm soát đối với hàng đợi để bạn biết họ sẽ không được sử dụng bởi các mã khác, nhưng nó có thể rằng mã bên Queue<T> sẽ khóa trên this. Đó có lẽ không phải là trường hợp, nhưng đó là điều mà tôi sẽ lo lắng.

Về cơ bản, tôi mong rằng .NET đã không thực hiện phương pháp tiếp cận Java của "một màn hình cho mọi đối tượng" - Tôi muốn Monitor là một lớp học nhanh.

(tôi giả sử bạn chỉ thực sự đọc khỏi từ điển từ nhiều luồng? Đó không phải là an toàn để sử dụng từ điển cho đa luồng đọc/ghi.)

+0

Tôi chỉ ghi vào hàng đợi khi nó trống. Tôi bỏ qua phần đó trong mã của tôi ở trên để đơn giản. Nhưng hàng đợi nên được khóa trong trường hợp đó, do đó, viết cho nó nên đặt ra không có vấn đề. – Ben

+1

Nhưng sử dụng 'System.Object' đơn giản không hoạt động đối với một số đối tượng khóa không xác định. – Ben

+0

@Ben: Bạn có thể sử dụng từ điển của các đối tượng khóa chuyên dụng, một cho mỗi trường hợp của 'Queue '. Tôi vẫn không thấy lý do tại sao bạn đang sử dụng 'Queue ' thay vì ['ConcurrentQueue '] (http://stackoverflow.com/a/16984743/45914). – jason

2

Thực tế là nó là một yếu tố trong một từ điển phần lớn là không liên quan - miễn là nó là kiểu tham chiếu (trong đó Queue<string>) - sau đó mỗi hàng đợi, khi được tìm nạp từ điển, sẽ giống như một cá thể object mỗi lần. Điều này có nghĩa là nó sẽ hoạt động hoàn toàn hợp lý với khóa ở mức cho mỗi hàng đợi.

Vì vậy, về cơ bản: có, điều đó sẽ hoạt động tốt - miễn là Enqueue thực hiện cùng một khóa mỗi hàng đợi. Như Jon lưu ý - cho dù bạn nên làm điều đó là một câu hỏi khác.

Cá nhân, tôi vẫn có quan điểm rằng Monitor phải là loại không tĩnh và bạn chỉ có thể khóa Monitor trường hợp, thay vì bất kỳ object nào.

1

Vì vậy, câu hỏi của tôi là, nếu khóa một đối tượng trong từ điển sẽ hoạt động - giả sử giá trị của khóa (hàng đợi) không bao giờ bị thay đổi.

Nhìn vào mã của bạn ở đây:

lock (queue) { 
    if (queue.Count() > 0) { 
     res = queue.Dequeue(); 
    } 
} 

Bạn thể, nhưng tôi sẽ không làm điều này. Bạn nên never lock on the object itself, vì bạn có thể đang cạnh tranh với các chủ đề khác mã sẽ khóa trên cùng một đối tượng, bao gồm cả Queue<T> chính nó (người có thể khóa trên this).

Vì vậy, ở mức tối thiểu, bạn nên tạo một đối tượng khóa chuyên dụng cho mỗi hàng đợi.

Nhưng, có lý do nào khiến bạn không sử dụng ConcurrentQueue<T> không? Đó sẽ là giải pháp đơn giản nhất, và di chuyển gánh nặng của việc đưa nó vào Khung.

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