2013-08-06 28 views
31

Tôi đã viết bản thân mình một máy phát điện đa luồng ngẫu nhiênlĩnh vực Khởi tạo ThreadStatic vẫn gây NullReferenceException

public static class MyRandGen 
{ 
    private static Random GlobalRandom = new Random(); 
    [ThreadStatic] 
    private static Random ThreadRandom = new Random(SeedInitializer()); 
    private static int SeedInitializer() 
    { 
     lock (GlobalRandom) return GlobalRandom.Next(); 
    } 

    public static int Next() 
    { 
     return ThreadRandom.Next(); 
    } 
} 

Tuy nhiên, nó ném cho tôi một NullReferenceException trên bắn Tiếp(), mà tôi không hiểu. Đó có phải là loại khởi tạo các trường ThreadStatic bị cấm không?

Tôi biết tôi chỉ có thể kiểm tra xem trường có được khởi chạy mọi lúc không, nhưng đó không phải là giải pháp mà tôi đang tìm kiếm.

+0

Tại sao không sử dụng ['Lazy ', nó có các tùy chọn an toàn chủ đề] (http://msdn.microsoft.com/en-us/library/ee808725.aspx) – Mgetz

+0

Mã của bạn hoạt động không có ngoại lệ cho tôi. VS2010 \ 4.0 –

+0

Tại sao không sử dụng 'Rngcryptoserviceprovider' là ThreadSafe –

Trả lời

45

Khởi tạo trường ThreadStatic hơi phức tạp. Đặc biệt có bối cảnh này:

Không chỉ định giá trị ban đầu cho các lĩnh vực được đánh dấu bằng ThreadStaticAttribute, vì khởi tạo như vậy chỉ xảy ra một lần, khi các nhà xây dựng lớp thực thi, và do đó ảnh hưởng đến chỉ có một chủ đề.

trong MSDN Docs. Điều này có nghĩa là thread chạy khi lớp được khởi tạo được giá trị ban đầu mà bạn đã xác định trong khai báo trường, nhưng tất cả các luồng khác sẽ có giá trị null. Tôi nghĩ rằng đây là lý do tại sao mã của bạn thể hiện hành vi không mong muốn được mô tả trong câu hỏi của bạn.

Giải thích đầy đủ hơn là ở this blog.

(đoạn từ blog)

[ThreadStatic] 
private static string Foo = "the foo string"; 

Các ThreadStatic được khởi tạo trong constructor tĩnh - mà chỉ thực hiện một lần. Vì vậy, chỉ có chuỗi đầu tiên được gán "chuỗi foo " khi hàm tạo tĩnh thực hiện. Khi được truy cập trong tất cả các chủ đề tiếp theo , Foo được để lại ở giá trị null không được tài trợ.

Cách tốt nhất để giải quyết vấn đề này là sử dụng thuộc tính để truy cập Foo prop.

[ThreadStatic] 
private static string _foo; 

public static string Foo { 
    get { 
    if (_foo == null) { 
     _foo = "the foo string"; 
    } 
    return _foo; 
    } 
} 

Lưu ý rằng không có nhu cầu cho một khóa trong thuộc tính tĩnh, bởi vì mỗi thread được hành động dựa trên các _foo đó chỉ là cho chủ đề đó. Không thể tranh luận với các chủ đề khác. Điều này được đề cập trong câu hỏi này: ThreadStatic and Synchronization

+0

Đó là câu trả lời tôi đã tìm kiếm. Tôi nghĩ tôi có thể tránh được việc kiểm tra không. Cảm ơn sự giúp đỡ của bạn. – Tarec

+0

Chủ đề getter đó có an toàn không? Nếu bạn có hai phương pháp có ái lực cho cùng một luồng, và cả hai đều được gọi là getter cùng một lúc, điều đó có thể không gây ra vấn đề tiềm năng. Không nên có một khóa? – cost

+2

@cost - Mỗi chuỗi có '_foo' của riêng nó và cùng một luồng không thể truy cập bộ thu thập nhiều hơn một lần cùng một lúc. Xem http: // stackoverflow.com/questions/1087599/là-this-a-thread-an toàn-cách-để-khởi tạo-một-threadstatic. Ngoài ra MSFT nói 'Bất kỳ thành viên tĩnh công cộng nào thuộc loại này là an toàn thread 'http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(v=vs.110).aspx – hatchet

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