2009-11-02 32 views
5

Giả sử tôi có một mô-đun có Hàng đợi trong đó..NET - Thread thread Queue.Enqueue có an toàn không?

Đối với các đơn vị khác để Enqueue, họ phải trải qua một chức năng:

public sub InsertIntoQueue(Obj) 
    MyQueue.Enqueue(Obj) 
end sub 

Nếu tôi đã nhiều luồng chạy và họ muốn gọi InsertIntoQueue(), là coi chủ đề này an toàn không?

Tôi đang trong ấn tượng rằng chỉ có một bản sao của các lệnh trong bộ nhớ cần thiết để thực hiện hàm InsertIntoQueue() ... điều này sẽ khiến tôi nghĩ rằng đây là luồng an toàn.

Tuy nhiên, tôi tự hỏi điều gì sẽ xảy ra khi hai chủ đề cố gắng chạy hàm cùng một lúc?

Chủ đề này có an toàn không và nếu không, làm thế nào tôi có thể làm cho chuỗi này an toàn? (và Điều gì sẽ là tác động hiệu quả liên quan đến tốc độ và sử dụng bộ nhớ)

Trả lời

4

Đây không phải là chủ đề an toàn.

Thành viên tĩnh công cộng (Được chia sẻ trong Visual Basic) thành viên này an toàn cho các hoạt động đa luồng. Các thành viên cá thể không được đảm bảo an toàn chỉ.

Từ MSDN Site.

tôi sẽ đề nghị thêm một đối tượng để đại diện cho xử lý đồng bộ để đối tượng của bạn

Dim SyncHandle as Object = new Object() 

Và sửa đổi phương pháp của bạn như vậy

Public Sub InsertIntoQueue(Object item) 
    SyncLock SyncHandle 
     MyQueue.Enqueue(item) 
    End SyncLock 
End Sub 
1

Một bộ hướng dẫn không có nghĩa là chỉ an toàn. Theo hướng dẫn, bạn luôn có một bộ.

Bây giờ, nhìn vào mẫu mã bạn đã cung cấp, không thể nói là chuỗi có an toàn hay không. Tất cả các bộ sưu tập tiêu chuẩn .NET, bao gồm cả Queue không phải là chủ đề an toàn, nhưng cung cấp cho bạn quyền truy cập vào một phiên bản được đồng bộ hóa của thmeselves.

Giờ đây, trong màn trình diễn hiệu suất, tất nhiên có hiệu suất đạt được, mức độ lớn - tùy thuộc vào phạm vi khóa và một số thứ khác. Đặc biệt sử dụng ổ khóa toàn cầu trong một ứng dụng web có thể trở thành một nút cổ chai nghiêm trọng dưới tải nặng

2

làm

SyncLock MyQueue 
    MyQueue.Enqueue(Obj) 
End SyncLock 

End Sub

0

Tại nguy cơ đi hơi off topic của OP, cần xem xét với các phương thức khác của hàng đợi. Tôi cho rằng có ít nhất một đối tượng dequeuing thread, và có thể bạn cũng đang kiểm tra xem hàng đợi có trống không?

Từ góc nhìn dequeue nếu bạn có nhiều hơn một chuỗi khử, và kiểm tra xem hàng đợi có trống không trước khi gọi dequeue (để ngăn chặn ngoại lệ hoạt động không hợp lệ) thì hoàn toàn có khả năng là một chuỗi (chuỗi a) có thể dequeue mục cuối cùng trong hàng đợi, inbetween một thread (thread b) đọc rằng hàng đợi là không có sản phẩm nào và nó gọi dequeue, do đó thread a sẽ gây ra ngoại lệ hoạt động không hợp lệ.

Bạn có thể đặt khóa xung quanh kiểm tra để trống và dequeue để giải quyết vấn đề này.

Thisthis là điều thú vị về chủ đề an toàn, và cũng có thể tôi có thể khuyên bạn nên đọc this và/hoặc this, trong khi họ không phải là tất cả trong vb.net họ giải thích luồng một cách chi tiết.

+0

Kế hoạch của tôi là có nhiều chủ đề Enqueuing, và một sợi chỉ khóa và xả toàn bộ hàng đợi tại các khoảng nhất định. –

+0

nếu bạn khóa trong khi bạn xử lý tất cả các đối tượng trong hàng đợi, tất cả các chủ đề được enqueuing sẽ được chặn (nếu họ cố gắng để enqueue) cho đến khi dequeue thread của bạn đã hoàn thành, bạn có thể tốt hơn để khóa chỉ kiểm tra trống và dequeue của mỗi đối tượng thay vì xử lý toàn bộ hàng đợi. – Matt

0

Tôi không phải là chuyên gia về an toàn luồng nhưng tôi đang cố gắng tìm hiểu càng nhiều càng tốt về vấn đề đó.

Tôi đã từng nghĩ (như bạn) rằng thao tác này có thể là an toàn luồng chỉ là ghi vào dữ liệu hàng đợi trên các chủ đề khác nhau và không có dequeue đang được thực hiện. Nhưng khi một người nào đó đã giải thích ở đây (và ở khắp mọi nơi tại các tài liệu MSDN):

tĩnh công cộng (chung trong Visual Basic) thành viên của loại này là an toàn cho hoạt động đa luồng. Ví dụ: thành viên không được đảm bảo là an toàn chỉ.

Điều đó có nghĩa rằng có lẽ trong nội bộ các MyQueue.Enqueue(Obj) được thực hiện như thế này:

  1. dữ liệu Đặt trên Queue();
  2. Con trỏ xếp hàng đợi;

Nếu nó được thực hiện theo cách này, bạn sẽ gặp vấn đề về luồng vì bạn có thể thấy bạn có thể ghi đè cùng một vị trí trên hàng đợi với hai chủ đề vì bài viết đang viết sau khi đã làm như vậy nhưng chưa đã có thể tăng con trỏ rồi. Có điều này trong tâm trí bạn có một số tùy chọn như đã nêu ở đây, khóa trên phương thức Enqueue(), sử dụng Queue.Synchronized() hoặc thậm chí có thể đơn giản hơn nhưng với tác động lớn hơn đến hiệu suất, khóa trên thuộc tính riêng khi truy cập vào Hàng đợi đối tượng theo cách này (vì mọi thứ bạn làm với Hàng đợi sẽ không phải là chủ đề an toàn):

Private ReadOnly Property MyQueue() as Queue 
Get 
    SyncLock (m_myQueueLock) 
     Return m_myQueue 
    EndSyncLock 
End Get 
End Property 

Hy vọng điều này sẽ hữu ích!

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