Синхронизация потоков между многопоточными файлами, обращающимися к одноэлементному объекту - PullRequest
0 голосов
/ 18 октября 2019

Я хочу выяснить, есть ли лучший способ для кода ниже с точки зрения надежного кода и чистого кода.

// Encryption is singleton via IoC
public class Encryption{

        private volatile ConcurrentDictionary<string, string> _blobs = new ConcurrentDictionary<string, string>();
        private object _encryptedDataLock = new object();
        public string CreateEncryptedData(string key)
        {
            string encryptedData = string.Empty;

            if (_cloudBlobs.ContainsKey(key))
                encryptedData = _blobs[key];

            lock (_encryptedDataLock)
            {

                if (!_cloudBlobs.ContainsKey(key))
                {
                    encryptedData = CalulateEncryptedData();
                    _blobs.TryAdd(key, encryptedData);

                    return encryptedData;

                }
            }

            return encryptedData;
        }
}

Обновление

Iищу решение, которое не использует объект блокировки, двойную проверку, изменчивый, как можно меньше кода явно.

1 Ответ

0 голосов
/ 18 октября 2019

Если два потока вызывают CreateEncryptedData с одним и тем же ключом в одно и то же время, возможны три результата:

  1. CalulateEncryptedData() вызывается ровно один раз, оба потока получают результат, и эторезультат сохраняется в _blobs.
  2. CalulateEncryptedData() вызывается дважды, но результат одного из вызовов отбрасывается. Оба потока получают один и тот же результат, и этот результат также сохраняется в _blobs.
  3. CalulateEncryptedData() вызывается дважды, и оба потока получают разные результаты. Один из результатов хранится в _blobs. Очевидно, что это нежелательно.

Если вам нужен случай 1, то вам нужен отдельный объект блокировки, но вы можете написать его так:

public string CreateEncryptedData(string key)
{
    if (_blobs.TryGetValue(key, out var value))
        return value;

    lock (_encryptedDataLock)
    {
        return _blobs.GetOrAdd(key, x => CalulateEncryptedData());
    }
}

Если случай 2 в порядкеВы можете еще упростить до этого:

public string CreateEncryptedData(string key)
{
    return _blobs.GetOrAdd(key, x => CalulateEncryptedData());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...