Reputation: 1616
As is, in the below code TextProgress
ends up not equal to TextMax
due to thread safety. If I place a lock on _ViewModel
for `_ViewModel.TextProgress++' this will correct this behaviour.
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace Testing
{
public partial class MainWindow : Window
{
ResultsItemViewModel _ViewModel = new ResultsItemViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _ViewModel;
_ViewModel.TextMax += 10000;
_ViewModel.TextMax += 10000;
}
private int MAXVAL = 10000;
private void Method1(
Action<int> reportProgress = null)
{
var progress = 0;
for (int i = 0; i < 10000; i++)
{
if (reportProgress != null)
reportProgress.Invoke(++progress);
else
{
_ViewModel.TextProgress++;
}
}
}
private void Method2(
Action<int> reportProgress = null)
{
var progress = 0;
for (int i = 0; i < 10000; i++)
{
if(reportProgress != null)
reportProgress.Invoke(++progress);
else
{
_ViewModel.TextProgress++;
}
}
}
private async Task TextProcessing()
{
await Task.WhenAll(
Task.Run(() => Method1()),
Task.Run(() => Method2()));
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
_ViewModel.TextProgress = 0;
await TextProcessing();
lblResult.Content = _ViewModel.TextProgress + "/" + _ViewModel.TextMax;
}
}
public class ResultsItemViewModel : INotifyPropertyChanged
{
int _textProgress, _textMax;
public int TextProgress
{
get => _textProgress;
set
{
_textProgress = value;
NotifyPropertyChanged();
}
}
public int TextMax
{
get => _textMax;
set
{
_textMax = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This works;
lock (_ViewModel)
{
_ViewModel.TextProgress++;
}
However, I have quite a few of these properties that need to be updated in this manner so I would prefer not to have to lock the whole _ViewModel
but at the same time I would prefer to not create a class for each property. Ideally I could do;
lock (_ViewModel.TextProgress)
{
_ViewModel.TextProgress++;
}
But this obviously isn't possible.
Upvotes: 0
Views: 87
Reputation: 169150
If you want thread-safety, you will either need to synchronize the access to the shared resource (TextProgress
) by for example using a lock, or you need to make sure that the shared resource is only accessed from a single thread. There is not much else you can do.
As an alternative to a using a lock
statement, you may use the Interlocked.Increment method to increment the value and store the result as an atomic operation.
But there is no "I do want multiple threads and thread-safety but I don't want to synchronize" option here I am afraid.
Upvotes: 1