Должен ли я использовать объект блокировки при клонировании ConcurrentDictionary в C #? - PullRequest
0 голосов
/ 16 апреля 2019

У меня есть кодовая база, в которой несколько потоков пишут в ConcurrentDictionary, и каждые 60 секунд другой поток запускается и клонирует основной CD, очищает его и продолжает свою работу на клонированном CD.Я хочу знать, не пропущу ли я некоторые данные, если я не использую lock, а Cloning and Clearing основной CD?Код для демонстрации проблемы выглядит следующим образом:


class Program
    {
        static object lock_obj = new object();

        static async Task Main(string[] args)
        {
            ConcurrentDictionary<string, ThreadSafeLong> cd = new ConcurrentDictionary<string, ThreadSafeLong>();


            Func<Task> addData = () =>
            {
                return Task.Run(async () =>
               {
                   var counter = 1;

                   while (true)
                   {
                       lock (lock_obj)
                       {
                           for (int i = 0; i < 100_000; i++)
                           {
                               cd.TryAdd($"{counter}:{i}", new ThreadSafeLong(i));
                               //WriteLine(i);
                           }
                           WriteLine($"Round {counter}");
                       }
                       counter++;
                       await Task.Delay(1_000);
                   }
               });
            };

            Func<Task> writeData = () =>
            {
                return Task.Run(async () =>
              {
                  while (true)
                  {
                      var sw = Stopwatch.StartNew();

                      lock (lock_obj) // to clone the data, and prevent any other data to be added while clone
                      {
                          var cloned = new ConcurrentDictionary<string, ThreadSafeLong>(cd);
                          cd.Clear();
                          WriteLine($"Cloned Count: {cloned.Count}");
                      }

                      sw.Stop();
                      WriteLine($"Elapsed Time: {sw.ElapsedMilliseconds}");

                      await Task.Delay(6_000);
                  }
              });
            };

            await Task.WhenAll(addData(), writeData());

        }
    }

PS: Как-то может быть связано с вопросом здесь

1 Ответ

3 голосов
/ 16 апреля 2019

В этих случаях я бы заменил словарь новым вместо вызова clear:

lock (lock_obj)
{
    var cloned = cd;
    cd = new ConcurrentDictionary<string, ThreadSafeLong>();
}

В этом случае другие потоки заканчивают запись в старый или уже работают с новым.

...