Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 142 стр.

UptoLike

Методы Allocate... и GetNamedDataSlot позволяют выделить новую
ячейку в TLS памяти (или получить существующую именованную), мето-
ды GetData и SetData позволяют получить или сохранить ссылку на объект
в TLS памяти. Использование TLS памяти в .NET менее удобно и эффек-
тивно, чем в Win32 API, но это связано не с реализацией TLS, а с реализа-
цией потоков:
Во-первых, возможно размещение данных в TLS памяти только
текущего потока, то есть нельзя положить данные до запуска по-
тока.
Во-вторых, процедура потока не получает аргументов, то есть
требуется предусмотреть отдельный механизм для передачи дан-
ных в функцию потока, а этот неизбежно реализуемый меха-
низм окажется конкурентом существующей реализации TLS па-
мяти.
В-третьих, использование TLS памяти в асинхронно вызывае-
мых процедурах может быть ограничено теми соображениями,
что заранее нельзя предугадать поток, который будет выполнять
эту процедуру.
В-четвертых, использование методов ООП часто позволяет со-
хранить специфичные данные в полях объекта, вообще не при-
бегая к выделению TLS памяти.
7.3.5. Таймеры
.NET предлагает два вида таймеров: один описан в пространстве имен
System.Timers, а другой – в пространстве имен System.Threading.
Таймер пространства имен System.Threading является опечатанным и
предназначен для вызова указанной асинхронной процедуры с заданным
интервалом времени.
Таймер пространства имен System.Timers может быть использован
для создания собственных классов-потомков – в нем вместо процедуры
асинхронного вызова применяется обработка события, с которым может
быть сопоставлено несколько обработчиков. Кроме того, этот таймер мо-
жет вызывать обработку события конкретным потоком, а не произволь-
ным потоком пула:
using System;
using System.Timers;
namespace TestNamespace {
class TestTimer : Timer {
private int m_minimal, m_maximal, m_counter;
public int count { get{ return m_counter – m_minimal; }}
Разработка параллельных приложений для ОС Windows
271
Конечно, аналогичного эффекта можно было бы добиться, просто
используя блокировку (lock или методы класса Monitor) при доступе к объ-
екту. Однако, такой подход потребует наложить блокировку исключитель-
ного доступа при чтении данных, что не эффективно. В обычных услови-
ях вполне допустимо чтение данных несколькими одновременно выпол-
няющимися потоками, что может дать заметное ускорение.
7.3.4.3. Локальная для потока память
Применение локальной для потока памяти в .NET опирается на TLS
память, поддерживаемую операционной системой. Аналогично Win32
API, возможны декларативный и императивный подходы для работы с ло-
кальной для потока памятью.
Декларативный подход сводится к использованию атрибута
ThreadStaticAttribute перед описанием любого статического поля. На-
пример, в следующем фрагменте:
class SomeData {
[ThreadStatic]
public static double xxx;
...
Поле класса SomeData.xxx будет размещено в локальной для каждого
потока памяти.
Императивный подход связан с применением методов
AllocateDataSlot, AllocateNamedDataSlot, GetNamedDataSlot,
FreeNamedDataSlot, GetData и SetData класса Thread. Использование этих
методов очень похоже на использование Tls... функций Win32 API, с той
разницей, что вместо целочисленного индекса в TLS массиве потока (как
это было в Win32 API) используется объект типа LocalDataStoreSlot, кото-
рый выполняет функции прежнего индекса:
class SomeData {
private static LocalDataStoreSlot m_tls = Thread.AllocateDataSlot();
public static void ThreadProc() {
Thread.SetData( m_tls, ... );
...
}
public void Main() {
SomeData sd = new SomeData();
...
// создание и запуск потоков
}
}
270
CIL и системное программирование в Microsoft .NET
270                           CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                    271


      Конечно, аналогичного эффекта можно было бы добиться, просто                     Методы Allocate... и GetNamedDataSlot позволяют выделить новую
используя блокировку (lock или методы класса Monitor) при доступе к объ-          ячейку в TLS памяти (или получить существующую именованную), мето-
екту. Однако, такой подход потребует наложить блокировку исключитель-             ды GetData и SetData позволяют получить или сохранить ссылку на объект
ного доступа при чтении данных, что не эффективно. В обычных услови-              в TLS памяти. Использование TLS памяти в .NET менее удобно и эффек-
ях вполне допустимо чтение данных несколькими одновременно выпол-                 тивно, чем в Win32 API, но это связано не с реализацией TLS, а с реализа-
няющимися потоками, что может дать заметное ускорение.                            цией потоков:
                                                                                         • Во-первых, возможно размещение данных в TLS памяти только
7.3.4.3. Локальная для потока память                                                        текущего потока, то есть нельзя положить данные до запуска по-
     Применение локальной для потока памяти в .NET опирается на TLS                         тока.
память, поддерживаемую операционной системой. Аналогично Win32                           • Во-вторых, процедура потока не получает аргументов, то есть
API, возможны декларативный и императивный подходы для работы с ло-                         требуется предусмотреть отдельный механизм для передачи дан-
кальной для потока памятью.                                                                 ных в функцию потока, а этот неизбежно реализуемый меха-
     Декларативный подход сводится к использованию атрибута                                 низм окажется конкурентом существующей реализации TLS па-
ThreadStaticAttribute перед описанием любого статического поля. На-                         мяти.
пример, в следующем фрагменте:                                                           • В-третьих, использование TLS памяти в асинхронно вызывае-
                                                                                            мых процедурах может быть ограничено теми соображениями,
     class SomeData {                                                                       что заранее нельзя предугадать поток, который будет выполнять
       [ThreadStatic]                                                                       эту процедуру.
       public static double xxx;                                                         • В-четвертых, использование методов ООП часто позволяет со-
       ...                                                                                  хранить специфичные данные в полях объекта, вообще не при-
     Поле класса SomeData.xxx будет размещено в локальной для каждого                       бегая к выделению TLS памяти.
потока памяти.
     Императивный подход связан с применением методов                             7.3.5. Таймеры
AllocateDataSlot,        AllocateNamedDataSlot,       GetNamedDataSlot,                .NET предлагает два вида таймеров: один описан в пространстве имен
FreeNamedDataSlot, GetData и SetData класса Thread. Использование этих            System.Timers, а другой – в пространстве имен System.Threading.
методов очень похоже на использование Tls... функций Win32 API, с той                  Таймер пространства имен System.Threading является опечатанным и
разницей, что вместо целочисленного индекса в TLS массиве потока (как             предназначен для вызова указанной асинхронной процедуры с заданным
это было в Win32 API) используется объект типа LocalDataStoreSlot, кото-          интервалом времени.
рый выполняет функции прежнего индекса:                                                Таймер пространства имен System.Timers может быть использован
                                                                                  для создания собственных классов-потомков – в нем вместо процедуры
      class SomeData {                                                            асинхронного вызова применяется обработка события, с которым может
        private static LocalDataStoreSlot m_tls = Thread.AllocateDataSlot();      быть сопоставлено несколько обработчиков. Кроме того, этот таймер мо-
        public static void ThreadProc() {                                         жет вызывать обработку события конкретным потоком, а не произволь-
           Thread.SetData( m_tls, ... );                                          ным потоком пула:
           ...
        }                                                                              using System;
        public void Main() {                                                           using System.Timers;
           SomeData sd = new SomeData();
           ...                                                                         namespace TestNamespace {
           // создание и запуск потоков                                                  class TestTimer : Timer {
        }                                                                                  private int m_minimal, m_maximal, m_counter;
      }                                                                                    public int count { get{ return m_counter – m_minimal; }}