![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Разделение данных между потоками
Если некий метод запускается в нескольких потоках, только локальные переменные метода будут уникальными для потока. Поля объектов по умолчанию разделяются между всеми потоками. В пространстве имён 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; } }
|