2014-12-19 15 views
6

Ví dụ là đoạn mã sau chủ đề an toàn:Các hoạt động LINQ trên chuỗi bộ sưu tập đồng thời có an toàn không?

ConcurrentQueue<Guid> _queue = new ConcurrentQueue<Guid>(); 
     while(true) 
     { 
      for(int y = 0; y < 3; y++) 
      { 
       if(y % 3 == 0) 
       { 
        System.Threading.Tasks.Task.Run(() => _queue.Enqueue(Guid.NewGuid())); 
       } 
       else if (y % 3 == 1) 
       { 
        Guid x; 
        System.Threading.Tasks.Task.Run(() => _queue.TryDequeue(out x)); 
       } 
       else if(y % 3 == 2) 
       { 
        System.Threading.Tasks.Task.Run(() => 
        { 
         if (_queue.Any(t => t == testGuid)) 
         { 
          // Do something 
         } 
        }); 

       } 
      } 

Chỉnh sửa: Rõ ràng danh hiệu là không đủ rõ ràng để cập nhật các mẫu mã để bao gồm hành vi luồng đa thực tế, có những mã trên chỉ là một mẫu của hành vi đa luồng.

+3

Chủ đề ở đâu? – leppie

+0

Bạn có thể có điều này trong một ứng dụng asp.net và nhiều chủ đề sẽ truy cập nó mà không cần bạn tạo chúng bằng tay – pollirrata

+1

Không có luồng đa trong mã của bạn nhưng nếu bạn đang ở trong môi trường đa luồng, ConcurrentQueue chắc chắn là loại tốt để sử dụng vì nó cung cấp truy cập an toàn vào hàng đợi của bạn .. – FloChanz

Trả lời

8

Hoạt động LINQ là chỉ đọc để chúng là chỉ an toàn trên tất cả bộ sưu tập. Tất nhiên, nếu bạn thêm mã sửa đổi bộ sưu tập bên trong phương thức Where hoặc Select, chúng sẽ không an toàn cho chuỗi.

Bộ sưu tập an toàn chủ đề đảm bảo rằng sửa đổi là an toàn chủ đề, điều này thực sự không đáng lo ngại khi thực hiện truy vấn LINQ.

Điều gì không phải là an toàn đang sửa đổi bộ sưu tập trong khi truyền tải. Bộ sưu tập bình thường làm mất hiệu lực vòng lặp khi chúng được sửa đổi, trong khi các bộ sưu tập chủ đề an toàn thì không. Trong một số trường hợp, (ví dụ như trong ConcurrentQueue), điều này đạt được bằng cách trình bày ảnh chụp nhanh dữ liệu trong khi lặp lại.

+0

Cảm ơn, đó là những gì tôi đã làm sau. Vì vậy, nếu tôi muốn thực hiện các hoạt động LINQ và sửa đổi bộ sưu tập loại trừ lẫn nhau thì tôi phải triển khai bộ sưu tập khóa của riêng mình. – AncientSyntax

+0

Điều đó tùy thuộc. Nó có thể hữu ích ví dụ để bọc một hàng đợi trong một bộ sưu tập chặn và phơi bày dequeueing như là một enumerable. Sau đó, bạn có thể thực hiện các hoạt động LINQ trên đó nhưng chỉ chặn khi hàng đợi trống. Hoặc thực sự không chặn gì cả nhưng làm điều gì khác và sau đó quay lại và lặp lại các hoạt động LINQ. Điều này sẽ được đồng thời sửa đổi và làm công cụ LINQ, mà không cần khóa và với toàn thread-an toàn. –

+0

Vì vậy, điều đó có nghĩa rằng một khóa là cần thiết để tránh rằng ảnh chụp có chứa dữ liệu cũ trên một truy vấn LINQ dài hơn? Bạn vẫn còn dễ bị các vấn đề đa luồng khác. –

2

Vâng, theo documentation

Các System.Collections.Concurrent namespace cung cấp một số lớp học tập thread-safe nên được sử dụng ở vị trí của loại tương ứng trong System.Collections và System. Bộ sưu tập.Generic không gian tên bất cứ khi nào có nhiều chủ đề là truy cập vào bộ sưu tập đồng thời.

+1

[Tài liệu này] (http://msdn.microsoft.com/en-us/library/dd287144%28v=vs.110%29.aspx) sẽ hữu ích hơn vì nó nói cụ thể về cuộc gọi phương thức trên bộ sưu tập LINQ sẽ sử dụng. – Rawling

3

Có, nhưng ...

Hãy lấy ví dụ của bạn:

if(_queue.Any(t => t == testGuid)) 
{ 
    // Do something 
} 

Bây giờ điều này sẽ không, không có vấn đề gì đề khác đang làm, thất bại với một ngoại lệ, ngoại trừ trong cách ghi nhận (mà trong trường hợp này có nghĩa là không có ngoại lệ), đặt _queue vào trạng thái không hợp lệ hoặc trả về câu trả lời không chính xác.

Đó là, như vậy, an toàn chỉ.

Bây giờ làm gì?

Mã của bạn tại // Do something có lẽ chỉ được thực hiện nếu có phần tử trong hàng đợi khớp với testGuid. Thật không may, chúng tôi không biết điều này có đúng hay không, bởi vì dòng thời gian Heraclitan đã chuyển sang và tất cả những gì chúng tôi biết là có một Hướng dẫn trong đó.

Bây giờ, điều này không nhất thiết là vô dụng. Ví dụ, chúng tôi có thể biết rằng hàng đợi hiện chỉ đang được thêm vào (có thể luồng hiện tại là chỉ có duy nhất dequeues ví dụ, hoặc tất cả các dequeueing xảy ra trong điều kiện nhất định mà chúng ta biết là không tại chỗ). Sau đó, chúng tôi biết rằng vẫn còn có một guid trong đó. Hoặc chúng tôi chỉ có thể muốn gắn cờ rằng testGuid đã được xem liệu nó vẫn còn ở đó hay không.

Nhưng nếu // Do something phụ thuộc vào sự hiện diện của testGuid trong hàng đợi và hàng đợi bị xóa, thì toàn bộ khối mã không an toàn chỉ mặc dù biểu thức liên kết là.

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