在 C# 中克隆 ConcurrentDictionary 时应该使用锁定对象吗?
Should I use a lock object while Cloning a ConcurrentDictionary in C#?
我有一个代码库,其中多个线程写入 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: 不知何故可能与问题有关 here
在这些情况下,我会用新字典替换字典而不是调用 clear:
lock (lock_obj)
{
var cloned = cd;
cd = new ConcurrentDictionary<string, ThreadSafeLong>();
}
在那种情况下,其他线程已完成对旧线程的写入或已经在使用新线程。
我有一个代码库,其中多个线程写入 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: 不知何故可能与问题有关 here
在这些情况下,我会用新字典替换字典而不是调用 clear:
lock (lock_obj)
{
var cloned = cd;
cd = new ConcurrentDictionary<string, ThreadSafeLong>();
}
在那种情况下,其他线程已完成对旧线程的写入或已经在使用新线程。