синхронизация доступа и использованием async await

Пример описанной проблемы, будет ниже и это лишь тестовый пример для наглядности иллюстрирующий вопрос.

Вопрос следующий, как правильно синхронизировать доступ к разделяющим рессурсам при использовании async/await ? Мне нужно вызвать ряд методов которые будут менять состояние объекта путем отсылке команд по сети. Эти методы должны быть вызваны последовательно и их вызов должен быть под локом. Как известно нельзя локировать async/await вызовы, однако как правильно поступать в данной ситуации? В приведенном примере я использовал SemaphoreSlim, однако в одном собственном проекте я имел проблемы с синхронизацией доступа не смотря на использование данного блокиратора.

В SemaphoreSlim есть методы асинхронного блокирования, однако как утверждает старший коллега по работе, он все равно может работать через раз с вызовами async/await, так как они внутри себя будут использовать тот же блокиратор. Плюс как пишут в сети, после await поток изменяется и блокиратор может пытаться освободить лок из потока отличного от того где лок был захвачен, что так же может привести к нежелательным результатам.

Иллюстрация вопроса следующая:

class DataUpdater
    {
        private string data;
        SemaphoreSlim semaphore = new(1);

        private async Task<string> UpdateToInternet(string newString) { throw new NotImplementedException(); }
        private async Task<string> ReadFromInternet() { throw new NotImplementedException(); }

        public async Task<string> UpdateFromInternet()
        {
            await semaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                data = await ReadFromInternet().ConfigureAwait(false);
            }
            finally
            {
                semaphore.Release();
            }
            return data;
        }

        public string ReadData()
        {
            semaphore.Wait();
            try
            {
                return data;
            }
            finally
            {
                semaphore.Release();
            }
        }
        public async Task<bool> ModifyData(string newData)
        {
            await semaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                string oldData = data;
                data = await UpdateToInternet(newData).ConfigureAwait(false);

                return data != oldData;
            }
            finally
            {
                semaphore.Release();
            }
        }
    }

Чем в данном примере можно заменить SemaphoreSlim в публичных методах? И как правильно делать синхронизацию в публичных методах? Интересует именно возможность блокирования вызова астнхронных методов. Как один из вариантов которые мне подсказали, это создавать очереди и метод разбирающий их где в очередь добавлять задание и затем при ее разборе в отдельном потоке гарантированно будет соблюдены последовательности вызовов, но это не удобно когда нужно вернуть значение сразу же. По этому хотелось бы найти возможность блокировать асинхронные вызовы.

Так же буду благодарен за ссылки по устройству механизма async/await.


Ответы (0 шт):