我可以翻译成中文:我能够嵌套关键段吗?TCriticalSection是可嵌套的吗?

3

我希望有两个程序可以相互调用,或者从任何正在运行的线程中被调用,但是一次只能运行一个。我该怎么做?这种方法是否可靠?

var
  cs: TCriticalSection;

procedure a;
begin
  cs.Acquire;
  try
    // Execute single threaded here. 
  finally
    cs.Release;
  end;
end;

procedure b;
begin
  cs.Acquire;
  try
    // Execute single threaded here. Maybe with calls to procedure a.
  finally
    cs.Release;
  end;
end;
2个回答

7
是的,这样可以。在同一个线程中,过程A可以调用B,反之亦然,并且当线程A正在使用过程A或B时,当线程B想要使用这些过程时,必须等待。
请参阅有关关键部分的MSDN文档:http://msdn.microsoft.com/en-us/library/ms682530%28VS.85%29.aspx 关键部分可以嵌套,但对于每个Acquire调用,您必须有一个Release调用。因为您在try .. finally子句中有Release调用,所以可以确保发生这种情况,因此您的代码是正确的。

1

虽然在Windows上可以多次获得临界区,但并非所有平台都支持此功能,其中一些将在尝试重新获得同步对象时阻塞。

这里实际上没有必要允许"嵌套"。如果您正确设计您的类,使得公共接口负责获取和释放临界区,而不是在实现方法中进行操作,并确保实现方法从不调用接口方法,那么您就不需要该特定功能。

另请参见Stack Overflow的问题"Recursive Lock (Mutex) vs Non-Recursive Lock (Mutex)",以了解递归互斥锁/临界区获取的一些缺点。


谢谢。我同意,只要类层次结构与需要锁定的事物相符,就没有必要嵌套,这在设计良好的情况下通常是成立的,但我认为可能会出现不符合情况的情况。(我的程序不是其中之一,我只是在作弊。) - soid
但是,如果您通过线程本地单例实现锁定,则没有任何方法可以从同一线程重新获取相同的临界区。并且每个使用情况仍然可以实现。在我看来,递归临界区只是没有真正(即“没有其他方法”)需要。 - mghie
@mghie:听起来是个不错的解决方案。谢谢。 - soid
@mghie:我感冒了,我的大脑无法理解使用线程本地单例进行锁定的方法。如果您能提供一个示例和该方法的解释链接,我将非常感激。 - Marjan Venema
@mghie:谢谢。这个缩写帮助我在谷歌上搜索。我理解RAII是为了保护资源,确保资源总是被释放。我想知道它是否能够防止多个线程之间的竞争条件导致的资源问题?如果每个线程都有一个锁,特别是TLS中的一个锁,那么每个线程都会有自己的锁,并且对受保护的资源的访问不会被序列化/同步化。这就是为什么您没有提出它作为替代方案的原因吗?但是建议采用适当的类设计(如您所描述的)来消除递归的需要。 - Marjan Venema
显示剩余2条评论

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