Як працює атрибут ThreadStatic?


138

Як працює [ThreadStatic]атрибут? Я припускав, що компілятор видасть якусь IL для того, щоб заповнити / отримати значення в TLS, але дивлячись на розбирання, схоже, це не робиться на цьому рівні.

У подальшому, що станеться, якщо ви поставите його на нестатичний член? У нас був розробник, який помилився, і компілятор навіть не видає попередження.

Оновлення

Тут відповіли друге питання: ThreadStatic модифіковано статичним C #


1
Якщо згенерований ІР такий же (який він насправді є), час виконання повинен бути кодується спеціально, щоб знати, як розподілити та прочитати значення, коли воно потрапляє на таке оформлене поле. Здається, хак :)
Rex M

Відповіді:


92

Семантика реалізації статичної нитки знаходиться нижче рівня IL в компіляторі .NET jit. Компіляторам, які випромінюють IL, як VB.NET і C #, не потрібно нічого знати про T32 Win32, щоб випромінювати код IL, який може читати та записувати змінну, яка має атрибут ThreadStatic. На зміну немає нічого особливого, наскільки C # знає - це просто місце для читання та написання матеріалів. Те, що у нього є атрибут, не має жодного наслідку для C #. C # потрібно знати лише, щоб передавати інструкції IL для читання або запису цього імені символу.

"Важкий підйом" виконується основним CLR, який відповідає за те, щоб IL працював над конкретною апаратною архітектурою.

Це також би пояснило, чому розміщення атрибута на невідповідному (нестатичному) символі не отримує реакції від компілятора. Компілятор не знає, якої особливої ​​семантики потрібен атрибут. Однак інструменти аналізу коду, такі як FX / Cop, повинні знати про це.

Ще один спосіб переглянути це: CIL визначає набір областей зберігання: статичне (глобальне) зберігання, зберігання членів та зберігання стеків. TLS не входить до цього списку, дуже ймовірно, оскільки TLS не потрібно бути в цьому списку. Якщо інструкцій з читання та запису ІЛ достатньо для доступу до TLS, коли символ позначений атрибутом TLS, чому IL повинен мати якесь спеціальне представлення або лікування для TLS? Це не потрібно.


Але чи не така особлива поведінка TLS, що залежить від впровадження, повністю не підриває "перевірену" точку продажу .NET / CLR?
Дай

116

Як працює атрибут [ThreadStatic]?

Можна подумати, що поле, позначене ThreadStatic , прикріплене до потоку, і його термін експлуатації порівнянний із терміном служби потоку.

Тож у псевдокоді ThreadStaticсхоже (за семантикою) надати ключ-значення, приєднане до потоку:

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

але синтаксис трохи простіше:

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

що трапиться, якщо поставити його на нестатичний член?

Я вважаю, що це ігнорується:

    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);
    }

Додатково варто зазначити, що ThreadStaticне потрібен жодний механізм синхронізації порівняно зі звичайними статичними полями (оскільки стан не є загальним).


1
По-друге, такий як псевдо-код повинен бути "MyClass.myVariable", чи не так?
akshay2000

Я не впевнений у точних обмеженнях, але я просто хотів зазначити, чи не очевидно, що це не повинно бути примітивним типом. Якщо ви подивитесь на джерело, TransactionScopeвони зберігають у ньому всілякі речі для сфери застосування ( referenceource.microsoft.com/#System.Transaction/System/… )
Simon_Weaver

10

[ThreadStatic] створює поодинокі версії тієї ж змінної у кожному потоці.

Приклад:

[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

Поле, позначене символом [ThreadStatic], створюється на локальному сховищі теми, тому кожен потік має власну копію поля, тобто область полів локальна для потоку.

Поля TLS - це доступ через регістри gs / fs сегментів. Ці сегменти використовуються ядрами ОС для доступу до потокової пам’яті. Компілятор .net не випускає жодної ІЛ для заповнення / отримання значення в TLS. Це робиться ядром ОС.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.