.NET 4.x Синхронизация обновления поля класса из двух разных методов - C#

Узнай цену своей работы

Формулировка задачи:

В общем, назрел вопрос. Может кто знает более удобный способ сделать синхронизацию обновления данных так, чтобы во время обновления этих данных вызов любого из методов, которые тоже могут обновлять эти данные ничего не делал. Есть 2 кнопки и 2 метода. Один генерит заявки и запускает их выполнение. Второй просто обновляет данные, которые используются для генерации заявок. Заявка - это какая-то работа программы, которая занимает определённый промежуток времени, суть не в этом. К примеру, нажали на кнопку "Запуск заявки". Пошла генерация, получение данных с сервера. Последующие нажатия уже данные с сервера не получаются, но новые заявки генерируются из старых данных. И есть кнопка "Обновить данные для генератора заявок". При нажатии на неё должен быть запрет на обновление этих данных из других методов. Точнее даже не именно запрет на обновление этих данных, а вообще работы методов, пока эти данные обновляются и неважно какой из методов инициировал обновление.
public class SomeViewModel : ViewModelBase
{
        private bool _generationOfAppsInProgress;
        private readonly object _generatorSync = new object();
        private RelayCommand _updateAppsGenData;
        private RelayCommand<ApplicationViewModel> _startExecutionCommand;
 
        private Task<AppsGenDataSet> GetDataForAppsGeneratorAsync()
        {
            Application[] apps = RootElements.Select(appVm => appVm.Model).ToArray();
 
            return Task<AppsGenDataSet>.Factory.StartNew(() =>
            {
                int[] mixerNumbers = _main.Mixers.Select(m => m.Number).ToArray();
 
                var carPairs = DataManager.Instance.GetAllCars(); //Обращение к серверу
                var cars = carPairs.Select(pair => pair.Data).ToArray();
 
                var clientPairs = DataManager.Instance.GetAllClients(); //Обращение к серверу
                var clients = clientPairs.Select(pair => pair.Data).ToArray();
 
                var recipePairs = DataManager.Instance.GetRecipes(0, 1000); //Обращение к серверу
                var recipes = recipePairs.Select(pair => pair.Data).ToArray();
 
                return new AppsGenDataSet(2, mixerNumbers, apps, recipes, cars, clients, CurrentUser.User);
            });
        }
 
        public async void StartAppExecution()
        {
            if (_generationOfAppsInProgress)
            {
                return;
            }
 
            lock (_generatorSync)
            {
                if (_generationOfAppsInProgress)
                {
                    Debug.WriteLine("Генерация заявок запущена ранее. Текущий вызов генерации заявок будет пропущен.");
                    return;
                }
 
                _generationOfAppsInProgress = true;
            }
 
            Application[] apps = RootElements.Select(appVm => appVm.Model).ToArray();
 
            if (_appsGenDataSet == null)
            {
                Debug.WriteLine("Набор данных для генератора заявок НЕ проинициализирован.");
                Debug.WriteLine("Получение данных для генератора заявок...");
 
                AppsGenDataSet data = await GetDataForAppsGeneratorAsync();
                _appsGenDataSet = data;
 
                Debug.WriteLine("Набор данных для генератора заявок проинициализирован.");
            }
            else
            {
                _appsGenDataSet.AppsFromQueue = apps;
            }
 
            Debug.WriteLine("Генерируем заявки.");
            Application[] generated = _appsGenerator.Generate(_appsGenDataSet);
            Debug.WriteLine("Сгенерировано заявок: {0}.", generated.Length);
 
            if (generated.Length > 0)
            {
                await Task.Run(() =>
                {
                    for (int i = 0; i < generated.Length; i++)
                    {
                        DataManager.Instance.AddApplication(generated[i]); //Обращение к серверу
                    }
                });
            }
 
            RunNextAvailableApplicationAsDemo();
 
            _generationOfAppsInProgress = false;
        }
 
        public RelayCommand UpdateAppsGenDataCommand
        {
            get
            {
                return _updateAppsGenData ?? (_updateAppsGenData = new RelayCommand(async () =>
                {
                    if (_generationOfAppsInProgress)
                    {
                        return;
                    }
 
                    lock (_generatorSync)
                    {
                        if (_generationOfAppsInProgress)
                        {
                            return;
                        }
 
                        _generationOfAppsInProgress = true;
                    }
 
                    AppsGenDataSet data = await GetDataForAppsGeneratorAsync();
                    _appsGenDataSet = data;
 
                    _generationOfAppsInProgress = false;
                }));
            }
        }
 
        public RelayCommand<ApplicationViewModel> StartExecutionCommand
        {
            get { return _startExecutionCommand ?? (_startExecutionCommand = new RelayCommand<ApplicationViewModel>(app => StartAppExecution())); }
        }
}
В коде выше основное на что следует обратить внимание это на одинаковый код в обоих методах:
            if (_generationOfAppsInProgress)
            {
                return;
            }
 
            lock (_generatorSync)
            {
                if (_generationOfAppsInProgress)
                {
                    Debug.WriteLine("Генерация заявок запущена ранее. Текущий вызов генерации заявок будет пропущен.");
                    return;
                }
 
                _generationOfAppsInProgress = true;
 
               //-----------------------
               //КАКАЯ-ТО РАБОТА
               //-----------------------
 
                _generationOfAppsInProgress = false;
            }
Как-то это неудобно так блокировать выполнение каких-либо манипуляций с данными, которые какой-то метод обновляет в данный момент времени.
При том, я думаю, понятно, что нельзя вызвав один из методов блокировать поток. Так-то можно было бы заюзать один из наследников WaitHandle

Решение задачи: «.NET 4.x Синхронизация обновления поля класса из двух разных методов»

textual
Листинг программы
        if (!enter.LockTaken)
          return;

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4.167 из 5