属性和线程安全

时间:2018-01-31 15:43:14

标签: c# wpf thread-safety

原样,由于线程安全,下面的代码TextProgress最终不等于TextMax。如果我在_ViewModel上锁定`_ViewModel.TextProgress ++',这将纠正此行为。

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));
        }
    }
}

这有效;

lock (_ViewModel)
{
    _ViewModel.TextProgress++;
}

但是,我有很多这些属性需要以这种方式更新,所以我宁愿不必锁定整个_ViewModel,但同时我宁愿不创建类对于每个属性。理想情况下,我可以做;

lock (_ViewModel.TextProgress)
{
    _ViewModel.TextProgress++;
}

但这显然是不可能的。

1 个答案:

答案 0 :(得分:1)

如果您想要线程安全,您需要通过例如使用锁来同步对共享资源(TextProgress)的访问,或者您需要确保仅从以下位置访问共享资源一个线程。你无能为力。

作为使用lock语句的替代方法,您可以使用Interlocked.Increment方法递增值并将结果存储为原子操作。

但是没有&#34;我确实想要多线程和线程安全,但我不想同步&#34;选择在这里我很害怕。