2011-12-25 33 views
5

tôi có phương pháp này:tuyên bố khóa không xuất hiện để được làm việc

public bool Remove(EntityKeyType key) 
{ 
    lock (syncroot) 
    { 
     //wait if we need to 
     waitForContextMRE.Wait(); 

     //if the item is not local, assume it is not remote. 
     if (!localCache.ContainsKey(key)) return false; 

     //build an expression tree 
     Expression<Func<EntityType, bool>> keyComparitorExpression = GenerateKeyComparitorExpression(key); 

     var itemToDelete = TableProperty.Single(keyComparitorExpression); 

     //delete from db 
     TableProperty.DeleteOnSubmit(itemToDelete); 
     DataContext.SubmitChanges(); 

     //get the removed item for OnCollectionChanged 
     EntityType itemToRemove = localCache[key]; 
     itemToRemove.PropertyChanged -= item_PropertyChanged; 

     //remove from the list 
     Debug.Assert(localCache.Remove(key)); 

     //call the notification 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, itemToRemove)); 
     return true; 
    } 
} 

Tôi gọi đó là từ nhiều chủ đề (gọi cùng một ví dụ), nhưng một ngoại lệ tục bị ném vào TableProperty.Single (Sequence chứa không có yếu tố nào). Sau khi gỡ lỗi mã tôi thấy rằng một tình huống đang được tạo ra, nơi các mục đang được xóa khỏi cơ sở dữ liệu sau khi một chủ đề khác nhau đã kiểm tra bộ nhớ cache cho sự tồn tại của nó. Điều này sẽ không thể trừ khi có nhiều luồng bên trong câu lệnh khóa (đối tượng syncroot chắc chắn là cùng một thể hiện trên các luồng).

Không thể? Tôi có bằng chứng: Impossible situation

Có ba chủ đề bên trong tuyên bố khóa! Đưa cái gì?

ghi chú:

  1. Các GDNCBM được thiết lập (không chặn).
  2. Đây không phải là trường hợp ngoại lệ bị ném, nó chỉ hiển thị nhiều chuỗi bên trong phần khóa. Cập nhật: Tôi đã thay đổi hình ảnh thành sự kiện intellitrace của ngoại lệ. Hình ảnh cũ là here
  3. Đối tượng đồng bộ hóa không tĩnh, vì tôi chỉ muốn các cuộc gọi đến cùng một thể hiện được đồng bộ hóa.

Cập nhật

Đây là tuyên bố của đối tượng SyncRoot:

private object syncroot = new object(); 

Và một số tờ khai khác:

private ManualResetEventSlim waitForContextMRE = new ManualResetEventSlim(true); 
private DataContextType _dataContext; 
private System.Data.Linq.Table<EntityType> _tableProperty; 
//DataContextType and EntityType are generic type parameters 

Tôi không thể làm cho SyncRoot tĩnh bởi vì tôi có một số trường hợp của lớp đang chạy và điều quan trọng là chúng không khối k mỗi khác. Nhưng điều đó không thực sự quan trọng - làm cho nó tĩnh không khắc phục được vấn đề.

ManualResetEvent (waitForContextMRE) không có để đồng bộ hóa - ở đó để chặn các thao tác cơ sở dữ liệu trong một thời gian nhất định sau khi thực hiện một số thao tác nhất định (tức là khi khởi động). Nó được đặt hầu hết thời gian. Lấy nó ra khỏi khối khóa cũng không khắc phục được sự cố.

+1

A: chúng ta có thể thấy nơi bạn đang khởi tạo 'syncroot', và B: bao lâu là bối cảnh đối tượng đá xung quanh? C: bạn có chắc rằng họ là cùng một ví dụ? Khó nói với trạng thái tạm dừng ... –

+1

Tôi khuyên bạn nên thêm thông báo dấu vết, với System.Diagnostics.Debug.WriteLine. Viết id luồng và mã băm đồng bộ hóa ở đầu và cuối khối khóa. Sau đó, bạn có thể dễ dàng nhìn thấy trong cửa sổ đầu ra nếu hai chủ đề trùng lặp với cùng một syncroot, mà chắc chắn không nên xảy ra. –

+0

Tác hại trong việc tạo đồng bộ hóa tĩnh là gì? –

Trả lời

0

Tôi đã gỡ lỗi vấn đề này một lúc và mặc dù tôi chưa giải quyết được vấn đề, rõ ràng là các khóa đang hoạt động.Tôi đoán vấn đề là với DataContext (được biết đến là khó khăn trong các tình huống đa luồng).

+0

Tôi đã tìm thấy vấn đề - 'Debug.Assert (localCache.Remove (key))' - Giống như trong C++ những thứ bên trong khẳng định không chạy trong chế độ phát hành, khiến các mục bị xóa khỏi cơ sở dữ liệu chứ không phải từ bộ nhớ đệm . –

3

Lời giải thích duy nhất tôi có là waitForContextMRE.Wait(); gọi điện thoại này làm cho các chủ đề không bỏ chặn syncroot! Và do đó, các chủ đề khác có thể nhập phần khóa. Hãy thử di chuyển waitForContextMRE.Wait(); trước khi khóa (...).

+0

Tôi không nghĩ rằng chúng ta có thể thấy đủ về waitForContextMRE để đưa ra bất kỳ kết luận nào ở đó; 'Monitor.Wait (syncroot)' là điều duy nhất có thể giải phóng khóa - và nó không rõ ràng với tôi rằng đây là cùng một –

+0

Tại sao gọi wait() nếu bạn đang ở trong khóa và giả sử không có quá trình khác bằng cách sử dụng các chủ đề? // đợi nếu chúng ta cần waitForContextMRE.Wait(); –

+0

Đã thử - nó không khắc phục được sự cố ... –

0

Tôi đề nghị khóa TableProperty hoặc DataContext

+5

Hết sức tò mò ... dựa trên? Các vấn đề về luồng quá phức tạp đến mức ** nên tránh bất kỳ phản ứng đầu gối nào **, và bất kỳ đề nghị nào cũng phải là: dựa trên bằng chứng, và b: bao gồm lý do –

+0

@Marc Gravell, cảm ơn :-) –

+0

nó thực sự là nghiêm trọng điểm tôi đã cố gắng để làm cho có ... –

3

Tôi nghĩ rằng bạn đang gọi các đối tượng khác nhau. Không có dấu hiệu trên ảnh chụp màn hình của bạn mà bạn đang dùng các giá trị từ các chủ đề khác nhau. Cũng sử dụng đồng bộ hóa tĩnh không phải là một ý tưởng tốt vì có thể dẫn đến các trường hợp như của bạn. Bạn có lý do thực sự mạnh mẽ để không có nó tĩnh?

+0

@Elastep Tôi đồng ý rằng bằng chứng là cùng một đối tượng khá thiếu - do đó yêu cầu của tôi để biết thêm thông tin dưới dạng nhận xét (chưa trả lời) ... –

+0

Nó cần phải không tĩnh vì sẽ có nhiều phiên bản của đối tượng không được chặn nhau. Mã này đang được gọi từ một thử nghiệm đơn vị và trong trường hợp đó chỉ có một ví dụ. –

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