Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базовые технологии платформы .NET.docx
Скачиваний:
11
Добавлен:
18.08.2019
Размер:
423.24 Кб
Скачать

32.4. Разделение данных между потоками

Если некий метод запускается в нескольких потоках, только локальные переменные метода будут уникальными для потока. Поля объектов по умолчанию разделяются между всеми потоками. В пространстве имён System определён атрибут [ThreadStatic], применяемый к статическим полям. Если поле помечено таким атрибутом, то каждый поток будет содержать свой экземпляр поля. Для [ThreadStatic]-полей не рекомендуется делать инициализацию при объявлении, так как код инициализации выполнится только в одном потоке.

public class SomeClass

{

public static int SharedField = 25;

[ThreadStatic]

public static int NonSharedField;

}

Для создания неразделяемых статических полей можно использовать тип ThreadLocal<T>. Перегруженный конструктор ThreadLocal<T> принимает функцию инициализации поля. Значение поля хранится в свойстве Value.

public class Slot

{

private static readonly Random rnd = new Random();

private static int Shared = 25;

private static ThreadLocal<int> NonShared =

new ThreadLocal<int>(() => rnd.Next(1, 20));

public static void PrintData()

{

Console.WriteLine("Thread: {0} Shared: {1} NonShared: {2}",

Thread.CurrentThread.Name,

Shared, NonShared.Value);

}

}

public class MainClass

{

public static void Main()

{

// для тестирования запускаем три потока

new Thread(Slot.PrintData) {Name = "First"}.Start();

new Thread(Slot.PrintData) {Name = "Second"}.Start();

new Thread(Slot.PrintData) {Name = "Third"}.Start();

Console.ReadLine();

}

}

Отметим, что класс Thread имеет статические методы AllocateDataSlot(), AllocateNamedDataSlot(), GetNamedDataSlot(), FreeNamedDataSlot(), GetData(), SetData(), которые предназначены для работы с локальными хранилищами данных потока. Эти локальные хранилища могут рассматриваться как альтернатива неразделяемым статическим полям.

Распространённый шаблон при разработке многопоточных приложений – неизменяемый объект (immutable object). После создания такой объект допускает только чтение своих полей, но не запись. Приведём пример класса, объекты которого являются неизменяемыми:

public class ProgressStatus

{

public readonly int PercentComplete;

public readonly string StatusMessage;

public ProgressStatus(int percentComplete, string statusMessage)

{

PercentComplete = percentComplete;

StatusMessage = statusMessage;

}

}

Достоинство неизменяемых объектов с точки зрения многопоточности заключается в том, что работа с ними требует коротких блокировок, обычно обрамляющих операции присваивания объектов:

public class WorkWithImmutable

{

private readonly object _locker = new object();

private ProgressStatus _status;

public void SetFields()

{

// создаём и настраиваем временный объект

var status = new ProgressStatus(50, "Working on it");

// переносим информацию, используя короткую блокировку

lock (_locker) _status = status;

}

public void ReadInfo()

{

// используя короткую блокировку, создаём временную копию

ProgressStatus statusCopy;

lock (_locker) statusCopy = _status;

// работаем с копией

int pc = statusCopy.PercentComplete;

string msg = statusCopy.StatusMessage;

}

}