System.RegularExpressions.TRegEx是线程安全的吗?

6

背景:我发现一个应用程序在多个线程中使用TRegEx单例。该单例在类构造函数中初始化为TRegEx.Create(Pattern, [roCompiled]),线程从RegEx.Match(Value).Groups开始使用它,但似乎没有使用同步机制,不过应用程序运行正常。不过,这只是TThread.Execute重载的一小部分,并且线程负载很小。因此,这可能仅仅是运气好,因为线程不太可能在关键部分相互交叉。

< p > < em >Thoughts:一方面,考虑到这一点,TRegEx实例只持有一个不可变(已编译)模式,并直接使用参数输入,或者在(TMatch)返回值中保留此输入以供可能的后续操作,例如NextMatch,它是在TMatch而非TRegEx上实现的。 潜在的开源 PCRE 库似乎是线程安全的。所有这些都符合上述情况。另一方面,我认为TRegEx实例通常不是线程安全的,因为例如,在function TRegEx.Match(const Input: String): TMatch(如上所示)中,要匹配的字符串似乎首先存储到实例中然后再进行匹配。并且同一个嵌套的TPerlRegEx实例通过各种函数链传递并保持活动状态。共享的TRegEx实例似乎需要受到保护,以防止协调不一致的访问,例如使用临界区域。

话虽如此,我怀疑TRegEx不是线程安全的,但我想询问一些了解多线程和裁定线程安全的专业人士进行确认。因此,我的问题非常普遍,独立于其所属应用程序:

问题:TRegEx是否线程安全?


一个 类构造器 只在单元初始化期间运行一次。所以它初始化的任何内容都将对使用该单元的所有线程可访问。因此多个线程共享 FRegEx 应该是安全的。你担心什么是不安全的呢?你能举个例子吗? - Remy Lebeau
@Remy,我已经添加了一个带有示例的解释,其中TRegEx不是线程安全的,我认为。 - Max
2
为什么你不能直接展示例子而不是摘录呢? - David Heffernan
@David 和 @Remy?这是关于 TRegEx 的问题,而不是让我提问的应用程序。恐怕我提供的背景信息分散了注意力。就 Delphi 提供的代码而言,我不确定应该引用多少内容来回答这个问题,也不确定如何判断引用和复制之间的界限——特别是当 StackOverflow 会永久保存我的决定时?然而,我所指的那些行只需要在 Match 上按 Ctrl 即可访问:RegEx.Match('')。对于这个问题,我或许应该提一下我的 Delphi 版本:它是 10.2。 - Max
如果您能提供一个代码示例,该示例可能会失败,如果您认为TRegEx的某个部分可能不是线程安全的,则实际上不是线程安全的。否则,这个问题就有点开放性了。 - Brian
我认为这是一个是非题,但我并不意味着它很容易评估。事实上,如果我没有发现底层库是线程安全的(我认为这很难做到),并且如果我的接口想法没有意义,我就不会提出这个问题。显然,我希望得到肯定的答复,但我也试图找到并支持否定的答案。最终,我感觉自己不够知识渊博。话虽如此,我不想调试应用程序,而是要得出更广泛使用的答案,并为更多人服务。也许有人注意到大部分工作已经完成,也许会将线程安全提升到TRegEx - Max
1个回答

1

Delphi的正则表达式类是基于PCRE库构建的,该库是线程安全的。请参见PCRE pcre_exec thread safe?

然而,Delphi包装器TRegex不是线程安全的。请考虑在TPerlRegEx.Match中调用pcre_exec时的情况:

OffsetCount := pcre_exec(FPattern, FHints, @FSubject[0], FStop, 0, Opts, @Offsets[0],
  High(Offsets));

这里的FSubjectOffsetsTPerlRegEx的成员,因此将在使用此实例的不同线程之间共享,而此实例又由TRegEx的实例拥有。

为了使TRegEx在您所期望的意义上是线程安全的(多个线程在共享编译后的正则表达式上执行匹配),这些变量需要对每个匹配函数调用进行私有化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接