【问题标题】:Unable to enter critical section无法进入临界区
【发布时间】:2017-11-29 10:21:03
【问题描述】:

为什么没有 Sleep(1) 就无法进入临界区?

type
  TMyThread = class(TThread)
  public
    procedure Execute; override;
  end;

var
  T: TMyThread;
  c: TRTLCriticalSection;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeCriticalSection(c);
  T := TMyThread.Create(false);
end;

procedure TMyThread.Execute;
begin
  repeat
    EnterCriticalSection(c);
    Sleep(100);
    LeaveCriticalSection(c);
    sleep(1);  // can't enter from another thread without it
  until false;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  EnterCriticalSection(c);
  Caption := 'entered';
  LeaveCriticalSection(c);
end; 

由于代码太多所以无法发布此文本文本文本文本文本。 哦,顺便说一句,如果该部分是由线程创建的,那么它工作正常。

【问题讨论】:

  • 因为机会之窗太窄了。线程放弃了该部分,但随后立即回收它。
  • 调用Sleep(1) 并没有做任何特别有趣的事情。您可能打算调用Sleep(0),而不是documented。另外,请更详细地编辑您的问题,而不是无用的占位符文本。
  • Sleep(0) 在我的情况下不起作用。只有 Sleep(>=1) 可以解决问题。无论如何,J...回答了我的问题。我不知道微软自 XP 以来改变了临界区的行为
  • 微软很可能已经改变了自 XP 以来关键部分的未定义行为。如果您做出超出记录范围的假设,当您被咬时不要感到惊讶:(
  • @MartinJames:这不是未定义的行为。这是一个实现细节。尽管本身定义良好,但编写依赖它的代码很脆弱,并且随时可能中断,因此我同意您评论的第二部分。

标签: multithreading winapi freepascal critical-section


【解决方案1】:

no guarantee that threads acquire a critical section on a FIFO basis (MSDN)。如果您当前的线程总是在释放临界区几微秒后重新获取临界区,那么任何其他等待的线程很可能永远不会及时唤醒以发现它自己可用。

如果您想更好地控制锁定顺序,可以使用其他同步对象。事件或队列可能是合适的,但我们并不真正知道您想要实现什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 2018-10-17
    • 2013-03-26
    • 2013-04-07
    • 2021-09-05
    相关资源
    最近更新 更多