我想知道下面的类是否是线程安全的,并在多线程上下文中完美地工作?
public class ThreadSafeClass
{
private List<int> commandList = new List<int>();
public void AddCommand(int newCommand)
{
lock(syncObj) {
commandList.Add(newCommand);
}
}
public List<int> Split()
{
List<int> oldList = commandList;
commandList = new List<int>();
return oldList;
}
}ThreadA周期性地调用split方法,许多线程调用AddCommand,split方法中的commandList指向内存中的某个列表,当新列表被赋值时,它的所有内容都在oldList中
split的目的是希望获得所有排队的命令,并在下一次调用中返回其余的命令,...同时让应用程序向commandList添加新项。
因为我专注于split方法,我忘记为add操作添加锁,因为它不是线程安全的,这要归功于:(can poyrazoğlu)但是Split的问题仍然存在。
发布于 2011-07-21 13:27:26
这里的问题归结为您对行为的期望。例如,以您的split方法为例:
public List<int> Split()
{
List<int> oldList = commandList;
commandList = new List<int>();
return oldList;
}在分配oldList和重新分配commandList之间有一段时间,AddCommand方法可以向commandList添加值,这些值将出现在oldList中
public List<int> Split()
{
// Say commandList contains 1 and 2
List<int> oldList = commandList;
// Now, on another thread, this happens:
//
// AddCommand 3
// AddCommand 4
// AddCommand 5
//
// The list hasn't been reassigned yet, so at this point oldList and
// commandList both have 1, 2, 3, 4, and 5.
commandList = new List<int>();
// Now, commandList is empty, and oldList contains 1, 2, 3, 4, and 5,
// even though it only contained 1 and 2 when you first assigned it.
return oldList;
}这个序列证明了这样一个事实:oldList不是只包含赋值时的值的快照,而是在赋值到重新赋值commandList之间实际上可以修改的快照。
这段代码中有一件事是正确的,即您添加的每个命令在oldList或commandList中只出现一次。不管有多少线程在调用AddCommand,你都不会遇到任何重复。这听起来像是您要实现的目标,所以我认为您的代码是正确的。
这是因为.NET reference assignment is atomic。在分配commandList期间,对AddCommand的调用不会导致值被添加到多个列表中或根本不被添加。
如果我误解了你的问题,请告诉我。
发布于 2011-07-21 03:06:18
该代码不是线程安全的,因为List.Add不能保证是安全的。(只是第一件事--还有其他问题)。
您也没有锁定共享数据(对commandList的任何访问权限)。
发布于 2011-07-21 03:07:00
拥有线程安全类并不意味着你的程序就是线程安全的。线程安全类只是意味着你可以从多个线程使用它,而且它仍然是好的。线程安全基本上意味着“在多线程环境中保持一致”。
List类不是线程安全的,所以你的代码绝对不是线程安全的。但是这个想法是,即使你使用线程安全的集合,也不意味着你的代码是线程安全的。
https://stackoverflow.com/questions/6767092
复制相似问题