У меня есть процесс, который занимает много времени, поэтому я хочу разбить его на потоки.Мой подход с многопоточностью прекрасно работает с Parallel.ForEach
, только я хочу сообщить пользователю, сколько переменных элементов мы обработали до сих пор.
Вот пример того, что я делаю.
namespace TestingThreading
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private int _idCounter;
public int IdCounter
{
get { return _idCounter; }
set
{
if (value != _idCounter)
{
_idCounter = value;
OnPropertyChanged("IdCounter");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public MainWindow()
{
InitializeComponent();
Counter.SetBinding(ContentProperty, new Binding("IdCounter"));
DataContext = this;
IdCounter = 0;
}
//random wait as a stand in for a variable length task
private void GetWait()
{
Random random = new Random();
int w = random.Next(3, 15);
System.Threading.Thread.Sleep(100 * w);
}
private async void CreateClientsButton_Click(object sender, RoutedEventArgs e)
{
//setup my a list of strings to iterate through
List<String> DeviceList = new List<string>();
for (int i = 0; i < 150; i++)
{
string ThisClient = "Fox" + i;
DeviceList.Add(ThisClient);
}
var myTask = Task.Run(() =>
{
Parallel.ForEach(DeviceList, new ParallelOptions { MaxDegreeOfParallelism = 15 }, device =>
{
GetWait();
IdCounter++;
// both below give compiler errors
//System.Threading.Interlocked.Add(ref IdCounter, 1);
//var c = Interlocked.Increment(ref DeviceCounter);
});
});
await myTask;
}
}
}
Привязка к интерфейсу работает, но я уверен, что на самом деле я не увеличиваю переменную столько раз, сколькоЯ должен быть.Например, это будет проходить 150 итераций, но после нескольких попыток я никогда не видел, чтобы мой счетчик был выше 146, что позволяет предположить, что существует состояние гонки, когда два потока пытаются обновить переменную одновременно.
Это не конец света, но я бы хотел сделать это «правильным путем», и мои исследования приводят меня к Interlock.Increment
или Interlock.Add
, но когда я пытаюсь увеличить свою переменнуюс любым из них я получаю эту ошибку:
Свойство или индексатор не могут быть переданы как параметр out или ref