2009-04-07 31 views
9

Tôi đang xem xét sử dụng một singleton trong dịch vụ Win đa luồng để ghi nhật ký và muốn biết một số vấn đề tôi có thể gặp phải là gì. Tôi đã thiết lập cá thể nhận để xử lý đồng bộ hóa vớiNhững mối nguy hiểm khi sử dụng Singleton trong ứng dụng đa luồng

private static volatile Logging _instance; 
    private static object _syncRoot = new object(); 

    private Logging(){} 
    public static Logging Instance 
    { 
     get 
     { 
      if (_instance==null) 
      { 
       lock(_syncRoot) 
       { 
        if (_instance == null) 
        { 
         _instance = new Logging(); 
        } 
       } 
      } 
      return _instance; 
     } 
    } 

Có điều gì khác mà tôi có thể cần phải lo lắng không?

+1

Đây là con rồng! Chạy trong khi bạn có thể. – Samuel

+1

“Không can thiệp vào công việc của con rồng; cho bạn giòn và có vị ngon với sốt cà chua. ” –

Trả lời

13

Điều đó có vẻ khá tốt đối với tôi.

Xem Implementing the Singleton Pattern in C# để biết thêm thông tin.

Chỉnh sửa: Có lẽ có thể đặt sự trở lại bên trong khóa.

+1

+1 để có liên kết tốt –

+0

và khóa trước khi so sánh mẫu với giá trị rỗng. –

+0

@Joel Thật sao? Đã không nghĩ về điều đó .... –

0

Tôi nghĩ rằng nếu phương pháp ghi nhật ký thể hiện là an toàn luồng thì không có gì phải lo lắng.

3

Singleton có khả năng trở thành nút cổ chai để truy cập vào tài nguyên được thể hiện bởi lớp và buộc truy cập tuần tự vào tài nguyên có thể được sử dụng song song.

Trong trường hợp này, đó có thể không phải là điều xấu, bởi vì bạn không muốn nhiều mục ghi vào tệp của bạn cùng một lúc, và thậm chí vì vậy tôi không nghĩ rằng việc triển khai của bạn sẽ có kết quả đó. Nhưng đó là điều cần lưu ý.

+0

Tôi thà tắc nghẽn sau đó sụp đổ, đó là những gì đã xảy ra khi tôi có nhiều hoạt động đó là lý do tôi nhìn vào sử dụng singleton. +1 để có thông tin chi tiết tốt –

1

Bạn đang sử dụng double-checked locking những gì được coi là chống mẫu. Wikipedia có các mẫu có và không có khởi tạo lười biếng cho các ngôn ngữ khác nhau.

Sau khi tạo cá thể đơn lẻ, tất nhiên bạn phải đảm bảo rằng tất cả các phương pháp đều an toàn chỉ.

12

Điều này mang tính thông tin hơn bất kỳ điều gì khác.

Những gì bạn đã đăng là thuật toán khóa được kiểm tra kép - và những gì bạn đã đăng sẽ hoạt động, theo như tôi biết. (Cũng như Java 1.5 nó cũng hoạt động ở đó.) Tuy nhiên, nó rất mong manh - nếu bạn nhận được bất kỳ sai sót nào, bạn có thể giới thiệu các điều kiện cuộc đua rất tinh tế.

Tôi thường thích để khởi tạo singleton trong initializer tĩnh: (. Thêm một constructor tĩnh nếu bạn muốn có một chút lười biếng thêm)

public class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    public static Singleton Instance 
    { 
     get { return instance; } 
    } 

    private Singleton() 
    { 
     // Do stuff 
    } 
} 

dễ dàng hơn mô hình đó để có được quyền, và trong hầu hết các trường hợp, nó cũng hoạt động tốt.

Có thêm chi tiết về số C# singleton implementation page của tôi (cũng được liên kết bởi Michael).

Vì sự nguy hiểm - tôi muốn nói rằng vấn đề lớn nhất là bạn mất khả năng kiểm tra. Có thể không phải là quá không hợp lệ để đăng nhập.

+0

liên kết tới bài viết của bạn bị hỏng. –

+0

Khá buồn, phải không? Đó là những mối nguy hiểm của việc đăng tải với một cảm giác hôi thối. Đã sửa lỗi, cảm ơn vì đã chú ý. –

+0

Lý do sử dụng tài sản ở đây là gì? Không đủ an toàn để sử dụng trường chỉ đọc tĩnh công khai không? –

1

Một gợi ý tốt hơn là thiết lập trình ghi nhật ký trong một bước thiết lập một luồng, vì vậy nó được đảm bảo ở đó khi bạn cần. Trong Windows Service, OnStart là một nơi tuyệt vời để làm điều này.

Một tùy chọn khác mà bạn có là sử dụng phương thức System.Threading.Interlocked.CompareExchange (T%, T, T): T để chuyển đổi. Nó ít gây nhầm lẫn và nó được đảm bảo để hoạt động.

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging()); 
+0

Tôi không phải là chuyên gia về C# nhưng tôi hy vọng điều này sẽ tạo ra một cá thể Ghi nhật ký mới trên mọi cuộc gọi. Phần 'New Logging()' được thực thi trước khi kiểm tra nguyên tử bên trong của InterlockedCompareExchange. –

+0

Bạn nói đúng. Làm thế nào xấu mà sẽ thực sự phụ thuộc vào ngữ nghĩa của các nhà xây dựng Logging (và initializers). Tôi giữ nó vẫn hoạt động, và đề nghị đầu tiên là tốt hơn. –

2

Bạn cần phải đảm bảo rằng mỗi phương pháp trong logger là an toàn để chạy đồng thời, ví dụ rằng họ không viết thư cho nhà nước chia sẻ mà không cần khóa thích hợp.

+0

Không sử dụng một singleton ngăn cản bạn chạy chúng đồng thời? Tôi nghĩ đó là vấn đề. –

+0

Không, nhiều chủ đề vẫn có thể truy cập vào cá thể Ghi nhật ký duy nhất. Phương pháp của nó * cần * để được an toàn chỉ. +1 cho việc này. – Lucas

+0

@bob: khóa kiểm tra kép của bạn ngăn không cho nhiều cá thể được tạo ra (để đảm bảo đơn), nó không ngăn cản truy cập đồng thời từ nhiều luồng. – Lucas

1

Có một số tranh luận về sự cần thiết phải thực hiện kiểm tra đầu tiên để sử dụng null Thread.VolatileRead() nếu bạn sử dụng mẫu kiểm tra kép và muốn nó hoạt động trên tất cả các kiểu bộ nhớ. Một ví dụ về cuộc tranh luận có thể được đọc tại http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/b1932d46-877f-41f1-bb9d-b4992f29cedc/.

Điều đó nói rằng, tôi thường sử dụng giải pháp của Jon Skeet từ bên trên.

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