3

我正在为多个项目编写一个库。它包含包含和操作数据的类。所以我想我应该在执行这些类的方法时锁定这些数据。但我也想如果必须进行线程安全的数据操作,那么让更高的应用层处理锁定。以后实际应用程序使用的类库的最佳实践是什么。

假设我有一堂课SpecialList。我该怎么办:

  • 调用方法时锁定数据
  • 如果他需要线程安全+忽略(索引)异常,让用户锁定列表,因此用户必须捕获它们

?

如果我知道 .NET Framework 类如何List处理,我也会这样做。


这些类没有明确针对单线程或多线程。他们只是在帮助各种用途的课程。

4

2 回答 2

5

如果您正在设计需要保证线程安全的数据结构和类型,那么请确保将锁和其他构造放入这些类型中以维护这些保证。

然而,仅有锁是不够的。

拿一本简单的字典。假设你想确保字典内部的数据结构不会被多个线程破坏,所以你引入了锁。但是,如果外部代码这样做:

if (!dict.ContainsKey(key))
    dict.Add(key, value);

那么这里不能保证在调用ContainsKeyand之间Add,其他一些线程还没有将该键添加到字典中。

因此,线程安全类型可能需要比简单锁更多的东西。可能需要一种方法,如果它不存在的话,可以安全地将键和值添加到字典中,在原子操作中,然后返回一个标志告诉你它做了什么,可能需要。

事实上,看这里:ConcurrentDictionary.TryAdd

我的建议是:

  1. 如果您需要这些保证,请通过需要安全和可预测的场景将类型设计为线程安全的,并专门实现这些
  2. 如果您不需要这些保证,请不要费心做任何事情,而只需记录该类型不是线程安全的,将其留给使用它的代码

.NET 类型List不以任何方式使用锁,除了一些关注线程安全的选定位置,特别是SyncRoot 属性

此外,编写良好的线程安全数据类型并不容易。只是在你需要的地方加锁可能会使它更加线程安全,但你会在性能方面付出巨大的代价。如果一个程序在使用它时不需要它是线程安全的,那么你仍然要付出很多代价。

编写高性能线程安全类型更难,并且通常不依赖锁(单独),而是使用自旋等待、特定 CPU 指令(其中一些可用于 .NET 代码)等。但这需要高度关于现代 CPU 如何执行代码的专业知识。

如果我是你,我会把线程安全留给专家,并从你自己的类型中删除它,除非你绝对需要它。

于 2013-08-07T09:43:25.710 回答
1

我认为答案取决于您是否希望您的库是线程安全的。这似乎微不足道,但这就是它的完成方式。考虑例如 .NET 的集合:

同步集合

列表(和其他基本集合 - 不是线程安全的)

所以一个不错的选择似乎是同时做两个版本,或者不是只做线程安全的版本。

于 2013-08-07T09:41:24.100 回答