可以从多个线程安全地访问静态数组吗?

时间:2012-04-16 13:25:58

标签: multithreading delphi delphi-xe2

如果保证每个线程只能读/写一个特定的数组子集,那么多个线程可以在同一个(静态)数组上工作而不需要求助于关键部分等吗?

编辑 - 这是针对非参考计数类型数组及其记录/打包记录的特定情况。

如果是,有任何警告吗?

我的直觉是肯定的,但我的直觉有时可能是不可靠的信息来源。

2 个答案:

答案 0 :(得分:8)

假设:

  1. 您有一个数组实例(静态或动态)和
  2. 数组的元素是纯值类型(即不包含引用)和
  3. 每个线程都在不相交的子数组上运行,
  4. 当线程在线程上运行时,系统中没有任何其他内容写入数组。
  5. 有了这些条件,我相信你的数据结构和线程模式都符合这些条件,那么所有算法都是线程安全的。

答案 1 :(得分:7)

不,在某些情况下,这可能不是线程安全的。

我至少看到两个原因。

1。它取决于静态数组内容。

如果您使用某些非引用计数类型(如double, integer, bytes, shortstring),则在大多数情况下不会出现任何问题(至少在读取/仅读取数据时)。

但是如果使用一些引用计数类型(如string, interface或嵌套动态数组),则必须注意线程安全。

那是:

TMyType1: array[0..1] of integer; // thread-safe on reading
TMyType2: array[0..1] of string;  // may be confusing

附加说明:如果您的string实际上在静态数组的某些子部分之间共享,则可能会混淆引用计数。除非你为每一个明确地调用UniqueString()(在一个关键部分内,我怀疑)。对于doubleinteger的数组,您将不会遇到此问题。

2。它取决于访问并发性

读取访问应该是线程安全的,即使对于引用计数类型,但并发写入可能会令人困惑。对于string,您可能会在某些随机情况下出现GPF问题,尤其是在多核CPU上。

一些安全的实施可能是:

  • 使用关键部分(尽可能小,以减少开销)或其他保护结构;
  • 确保使用 Copy-On-Write 或内容的私有线程副本;
  • 最新注释(不是关于安全性,而是性能):在多个CPU之间共享阵列可能会因CPU之间的缓存同步而导致性能下降。当您使用分离的数组时,性能有时要好得多,确保它们的L1缓存窗口不会在CPU之间共享。

请注意,在客户端,此类问题可能是调试的噩梦:多线程并发问题可能会随机发生,并且很难跟踪。更安全,更好,除非您有明确且经过验证的性能问题。

附加说明:对于双重静态数组的特定情况,只有一个线程访问数组的子部分,它是线程安全的。但是在所有情况下都没有绝对的线程安全规则,即使对于静态数组也是如此。只要您使用一些引用计数类型或某些指针,就可能出现随机问题。