C# C语言中关于线程的文档中的一个歧义#
在阅读乔·阿尔巴哈里(Joe Albahari)的优秀著作《C#中的线程技术》(Threading in C#)时,我遇到了以下模棱两可的句子: 线程安全类型不一定使使用它的程序成为线程安全的,后者所涉及的工作通常使前者成为冗余的 (您可以在上找到该句子;只需搜索“不确定性”即可快速跳转到相应的部分。) 我希望使用ConcurrentDictionary来实现某些线程安全的数据结构。这一段是否告诉我ConcurrentDictionary不能保证对数据结构的线程安全写入?有人能提供一个反例,说明线程安全类型实际上无法提供线程安全吗C# C语言中关于线程的文档中的一个歧义#,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,在阅读乔·阿尔巴哈里(Joe Albahari)的优秀著作《C#中的线程技术》(Threading in C#)时,我遇到了以下模棱两可的句子: 线程安全类型不一定使使用它的程序成为线程安全的,后者所涉及的工作通常使前者成为冗余的 (您可以在上找到该句子;只需搜索“不确定性”即可快速跳转到相应的部分。) 我希望使用ConcurrentDictionary来实现某些线程安全的数据结构。这一段是否告诉我ConcurrentDictionary不能保证对数据结构的线程安全写入?有人能提供一个反例,说明
提前感谢您的帮助。我对警告的理解是,仅仅因为您使用的是线程安全变量并不意味着您的程序是线程安全的
作为一个例子,考虑一个具有两个变量的类,该变量可以从两个线程中修改。仅仅因为这些变量是单独的线程安全的,并不能保证类修改的原子性。如果有两个线程修改这些变量,那么一个变量可能会以一个线程设置的值结束,而另一个变量则由另一个线程设置。这很容易破坏类的内部一致性。
我认为他的意思是,仅仅使用ConcurrentDictionary
而不是Dictionary
无处不在,并不会使程序线程安全。所以,如果你有一个非线程安全的程序,搜索和替换是没有帮助的;同样,在任何地方添加SynchronizedAttribute
也不会像魔法仙子一样奏效。对于集合来说尤其如此,迭代总是一个问题[1]
另一方面,如果将非线程安全的程序重新构造为更线程安全的设计,则通常不需要线程安全的数据结构。一种流行的方法是根据相互发送“消息”的“参与者”来重新定义程序——除了单个生产者/消费者样式的消息队列之外,每个参与者都可以独立运行,不需要在内部使用线程安全的数据结构
[1] BCL集合的第一个版本包括一些“线程安全”集合,这些集合在迭代过程中不是线程安全的。并发集合在迭代期间是线程安全的,但与其他线程的修改同时迭代。其他集合库允许对“快照”进行迭代,忽略其他线程的修改。最简单的情况是,线程安全列表或字典就是一个很好的例子;让每个操作都是线程安全的并不总是足够的—例如,“检查列表是否为空;如果为空,则添加一项”-即使所有操作都是线程安全的,也不能执行以下操作:
if(list.Count == 0) list.Add(foo);
因为它可能在两者之间发生变化。你需要同步测试<强>和Rechange。< P>这是一个含糊的陈述,但是例如,考虑一个类有两个成员,每个成员都是线程安全的,但是这两个成员都必须以原子方式更新。 在处理这种情况时,您可能会使整个操作原子化,从而使线程安全,从而使对单个成员的线程安全访问变得无关紧要
If并不意味着您的ConcurrentDictionary将以不安全的方式运行。前一段时间正在进行搜索,以解决我遇到的线程问题,并看到以下页面: 特别是“线程安全对象周围的锁定”部分 从页面: 有时还需要锁定访问线程安全对象的权限。为了举例说明,假设框架的List类确实是线程安全的,我们想向列表中添加一项: 不管这个列表是否是线程安全的,这个语句肯定不是
我的简明解释是这样的。线程安全有多种形式,满足一种形式的代码不会自动满足所有其他形式的代码。Roy 我猜你“过度阅读”了一个太简洁的句子。。。我认为这句话有两个意思:
ConcurrentDictionary
将始终通过从多个线程同时写入来保持一致的状态。另一个线程永远不会看到数据结构处于不一致状态
有人能提供一个
反例显示了一个
线程安全类型实际上无法
提供线程安全性
但是,从线程安全类型进行的一系列读写操作仍然可能会失败
if (!_list.Contains (newItem)) _list.Add (newItem);
void ExecutedByMultipleThreads(ConcurrentQueue<object> queue)
{
object value;
if (!queue.IsEmpty)
{
queue.TryDequeue(out value);
Console.WriteLine(value.GetHashCode());
}
}