Làm thế nào để thuộc tính ThreadStatic hoạt động?


138

Làm thế nào để [ThreadStatic]thuộc tính làm việc? Tôi giả định rằng trình biên dịch sẽ phát ra một số IL để nhét / lấy giá trị trong TLS, nhưng nhìn vào một sự tháo gỡ, nó dường như không làm điều đó ở mức đó.

Theo dõi, điều gì xảy ra nếu bạn đặt nó trên một thành viên không tĩnh? Chúng tôi đã có một nhà phát triển mắc lỗi đó và trình biên dịch thậm chí không đưa ra cảnh báo.

Cập nhật

Câu hỏi thứ hai được trả lời ở đây: ThreadStatic Được sửa đổi với Tĩnh C #


1
Nếu IL được tạo giống nhau (thực tế là như vậy), thì thời gian chạy phải được mã hóa cụ thể để biết cách phân bổ và đọc giá trị khi chạm vào trường được trang trí như vậy. Có vẻ như là một hack :)
Rex M

Câu trả lời:


92

Các ngữ nghĩa thực hiện của chủ đề tĩnh nằm dưới mức IL, trong trình biên dịch .NET jit. Các trình biên dịch phát ra IL như VB.NET và C # không cần biết gì về Win32 TLS để phát ra mã IL có thể đọc và viết một biến có thuộc tính ThreadStatic. Không có gì đặc biệt về biến số theo như C # biết - đó chỉ là một vị trí để đọc và viết nội dung. Việc nó có một thuộc tính trên đó không có kết quả đối với C #. C # chỉ cần biết để phát ra IL đọc hoặc viết hướng dẫn cho tên biểu tượng đó.

"Nâng vật nặng" được thực hiện bởi CLR cốt lõi chịu trách nhiệm làm cho IL hoạt động trên một kiến ​​trúc phần cứng cụ thể.

Điều đó cũng sẽ giải thích tại sao việc đặt thuộc tính vào một biểu tượng không phù hợp (không tĩnh) không nhận được phản ứng từ trình biên dịch. Trình biên dịch không biết ngữ nghĩa đặc biệt mà thuộc tính yêu cầu. Tuy nhiên, các công cụ phân tích mã như FX / Cop, nên biết về nó.

Một cách khác để xem xét nó: CIL định nghĩa một tập hợp các phạm vi lưu trữ: lưu trữ tĩnh (toàn cầu), lưu trữ thành viên và lưu trữ ngăn xếp. TLS không có trong danh sách đó, rất có thể vì TLS không cần phải nằm trong danh sách đó. Nếu IL đọc và viết hướng dẫn là đủ để truy cập TLS khi biểu tượng được gắn thẻ với thuộc tính TLS, tại sao IL phải có bất kỳ đại diện hoặc điều trị đặc biệt nào cho TLS? Nó không cần thiết.


Nhưng không phải hành vi đặc biệt, cụ thể về triển khai của TLS đã phá hủy hoàn toàn điểm bán "có thể kiểm chứng" của .NET / CLR?
Đại

116

Làm thế nào để thuộc tính [ThreadStatic] hoạt động?

Bạn có thể nghĩ rằng trường được đánh dấu bằng ThreadStatic được gắn vào một luồng và thời gian tồn tại của nó tương đương với tuổi thọ của một luồng.

Vì vậy, trong mã giả ThreadStaticcũng tương tự (theo ngữ nghĩa) với việc có một giá trị khóa được gắn vào một luồng:

Thread.Current["MyClass.myVariable"] = 1;
Thread.Current["MyClass.myvariable"] += 1;

nhưng cú pháp chỉ dễ hơn một chút:

class MyClass {
  [ThreadStatic]
  static int myVariable;
}
// .. then
MyClass.myVariable = 1;
MyClass.myVariable += 1;

Điều gì xảy ra nếu bạn đặt nó trên một thành viên không tĩnh?

Tôi tin rằng nó bị bỏ qua:

    class A {
        [ThreadStatic]
        public int a;
    }
    [Test]
    public void Try() {
        var a1 = new A();
        var a2 = new A();
        a1.a = 5;
        a2.a = 10;
        a1.a.Should().Be.EqualTo(5);
        a2.a.Should().Be.EqualTo(10);
    }

Ngoài ra, điều đáng nói là ThreadStatickhông yêu cầu bất kỳ cơ chế đồng bộ hóa nào so với các trường tĩnh thông thường (vì trạng thái không được chia sẻ).


1
Thứ hai giống như mã giả "MyClass.myVariable", nên không?
akshay2000

Tôi không chắc chắn các hạn chế chính xác, nhưng tôi chỉ muốn chỉ ra nếu không rõ ràng rằng nó không phải là một loại nguyên thủy. Nếu bạn nhìn vào các nguồn cho TransactionScopehọ lưu trữ tất cả các loại công cụ trong đó cho phạm vi ( referencesource.microsoft.com/#System.Transactions/System/... )
Simon_Weaver

10

[ThreadStatic] tạo các phiên bản riêng biệt của cùng một biến trong mỗi luồng.

Thí dụ:

[ThreadStatic] public static int i; // Declaration of the variable i with ThreadStatic Attribute.

public static void Main()
{
    new Thread(() =>
    {
        for (int x = 0; x < 10; x++)
        {
            i++;
            Console.WriteLine("Thread A: {0}", i); // Uses one instance of the i variable.
        }
    }).Start();

    new Thread(() =>
   {
       for (int x = 0; x < 10; x++)
       {
           i++;
           Console.WriteLine("Thread B: {0}", i); // Uses another instance of the i variable.
       }
   }).Start();
}

3

Trường được đánh dấu [ThreadStatic]được tạo trên Thread Local Storage để mỗi luồng có bản sao của trường đó, tức là phạm vi của các trường là cục bộ của luồng.

Các trường TLS được truy cập thông qua các thanh ghi phân đoạn gs / fs. Các phân đoạn này được sử dụng bởi các nhân hệ điều hành để truy cập bộ nhớ dành riêng cho luồng. Trình biên dịch .net không phát ra bất kỳ IL nào để nhét / truy xuất giá trị trong TLS. Nó được thực hiện bởi nhân hệ điều hành.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.