13 Возможности библиотеки Task Parallel Library. Проблемы синхронизации

Решение проблемы гонки данных требует применения средств синхронизации, позволяющих обеспечить взаимно-исключительный доступ к критической секции. Применение синхронизации гарантирует получение корректных результатов, но снижает быстродействие приложения. Чем больше размер критических секций в приложении, тем больше доля последовательного выполнения и ниже эффективность от распараллеливания. Для повышения быстродействия размер критической секции должен быть предельно минимальным – только те операторы, последовательность которых не должна прерываться другим потоком.

В следующем фрагменте каждый поток сохраняет в разделяемом массиве data данные из файла. Для обеспечения согласованного доступа к разделяемому ресурсу используются средства синхронизации.

// Поток №1
<Вход в критическую секцию>
StreamReader sr = File.OpenText(“file” + ThreadNum);
newValue = GetValue(sr);
data[cur_index] = newValue;
cur_index++;
sr.Close();
<Выход из критической секции>

Размер критической секции в этом фрагменте не оправдано большой. Действия по подготовке данных для сохранения (открытие файла, уникального для каждого потока; поиск и чтение необходимой информации) могут быть вынесены за критическую секцию:

// Поток №1
StreamReader sr = File.OpenText(“file” + ThreadNum);
newValue = GetValue(sr);
<Вход в критическую секцию>
data[cur_index] = newValue;
cur_index++;
<Выход из критической секции>
sr.Close();

Современные платформы для параллельного программирования, в том числе и среда Framework .NET, предлагают широкий выбор средств синхронизации. В каждой задаче применение того или иного инструмента синхронизации будет более эффективным. Например, для многопоточного увеличения разделяемого счетчика могут использоваться средства организации взаимно-исключительного доступа (объекты Monitor, Mutex), сигнальные сообщения (AutoResetEvent, ManualResetEventSlim), двоичные семафоры (Semaphore). Но максимально эффективным будет использование неблокирующих атомарных операторов (Interlocked.Increment).

Для работы с динамическими списками можно использовать как обычные коллекции с теми или иными средствами синхронизации, так и конкурентные коллекции с встроенной неблокирующей синхронизацией.