Инкремент глобальной переменой из таска
Как правильно увеличивать глобальную переменную внутри таска ?
А то получается что использую одни и те же числа по несколько раз(
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
List<int> listChisel = new List<int>();
int counter = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 100; i++)
{
listChisel.Add(i);
}
ZapuskPotokov(100);
}
private void ZapuskPotokov(int viborKolPotokov)
{
for (int i = 0; i < viborKolPotokov; i++)
{
Task.Run(() => Algoritm());
}
}
private void Algoritm()
{
Debug.WriteLine(listChisel[counter]);
counter++;
}
}
}
Ожидаю например: 195246837... - где все числа уникальны
Получаю: 000433221..
Ответы (1 шт):
Потому что переменная counter не потокобезопасна. 4 потока ее читают, потом 2 пишут, потом 3 читают, вразнобой. Чтобы исправить это, нужно сделать так, чтобы читать и писать в переменную мог одновременно только один поток. При чем между чтением и записью в одном потоке, другой поток не мог её ни читать, ни писать.
private object _locker = new object();
private void Algoritm()
{
int value;
lock (_locker)
{
value = listChisel[counter++];
}
Debug.WriteLine(value);
}
Или так, с учетом, что список ни кем не изменяется, пока работают потоки.
private object _locker = new object();
private void Algoritm()
{
int index;
lock (_locker)
{
index = counter++;
}
Debug.WriteLine(listChisel[index]);
}
Или даже так, с помощью атомарного инкремента
private void Algoritm()
{
int index = Interlocked.Increment(ref counter) - 1;
Debug.WriteLine(listChisel[index]);
}
В документации Interlocked.Increment ошибка в переводе на русский.
Возвращаемое значение
Int32Увеличиваемое значение.
Тогда как в английском
Returns
Int32The incremented value.
Что в переводе означает "увеличенное значение", а не увеличиваемое.
Кстати, Interlocked.Increment очень быстрый, ну потому что это всего одна аппаратная инструкция, и на ассемблере выглядит она так:
lock add dword ptr [rcx], 1
Где регистр rcx содержит адрес ref counter в памяти.