gpt4 book ai didi

multithreading - 为什么我的多线程应用程序关闭时有时会挂起?

转载 作者:行者123 更新时间:2023-12-03 18:56:53 25 4
gpt4 key购买 nike

我在应用程序中使用了几个关键部分。关键部分防止大型数据blob被不同的线程同时修改和访问。

AFAIK一切正常,除了有时退出时应用程序挂起。我想知道这是否与我对关键部分的使用有关。

有没有正确的方法来释放析构函数中的TCriticalSection对象?

感谢所有的答案。考虑到这些新信息,我将再次查看我的代码。干杯!

最佳答案

如Rob所说,唯一的要求是确保关键部分当前不属于任何线程。甚至没有要破坏它的线程。因此,就没有这样的模式可以正确地销毁TCriticalSection。只有您的应用程序必须采取措施才能确保的必要行为才会发生。

如果您的应用程序处于锁定状态,那么我怀疑这是负责任的任何关键部分的释放。正如MSDN所说(在Rob发布的链接中),DeleteCriticalSection()(最终是释放TCriticalSection调用的最终结果)不会阻塞任何线程。

如果您释放了其他线程仍在尝试访问的关键部分,则会出现访问冲突和其他意外行为,而不是死锁,因为此小代码示例应该可以帮助您演示:

implementation

uses
syncobjs;


type
tworker = class(tthread)
protected
procedure Execute; override;
end;


var
cs: TCriticalSection;
worker: Tworker;


procedure TForm2.FormCreate(Sender: TObject);
begin
cs := TCriticalSection.Create;

worker := tworker.Create(true);
worker.FreeOnTerminate := TRUE;
worker.Start;

sleep(5000);

cs.Enter;

showmessage('will AV before you see this');
end;

{ tworker }

procedure tworker.Execute;
begin
inherited;
cs.Free;
end;

添加到窗体的实现单元,根据需要更正FormCreate()事件处理程序的“TForm2”引用。

在FormCreate()中,这将创建一个关键部分,然后启动一个线程,其唯一目的是释放该部分。我们引入了Sleep()延迟来给线程时间进行初始化和执行,然后尝试自己进入关键部分。

我们当然不能,因为它已经被释放了。但是我们的代码不会挂起-尝试访问其他拥有的资源并不是死锁的,它只是被炸毁了,因为,好吧,我们正在尝试访问不再存在的资源。

您可以更加确定在这种情况下通过在关键部分引用空闲时对其进行NIL来创建AV。

现在,尝试将FormCreate()代码更改为此:
  cs := TCriticalSection.Create;

worker := tworker.Create(true);
worker.FreeOnTerminate := TRUE;

cs.Enter;
worker.Start;

sleep(5000);

cs.Leave;

showmessage('appearances can be deceptive');

这改变了一切……现在,主线程将获得关键部分的所有权-工作线程现在将释放关键部分,而仍由主线程拥有。

但是,在这种情况下,对cs.Leave的调用不一定会导致访问冲突。在这种情况下(发生),所有发生的事情是允许拥有线程按预期的方式“离开”该节(这当然不是,因为该节已消失,但在线程中似乎已经拥有了该节)。离开先前输入的部分)...

...在更复杂的情况下,可能会发生访问冲突或其他错误,因为以前在关键部分对象中使用的内存可能会在您调用它的Leave()方法时重新分配给其他对象,从而导致某些错误调用其他未知对象或访问无效的内存等。

同样,更改worker.Execute()以使其在释放后成为关键部分引用,它将确保在尝试调用cs.Leave()时发生访问冲突,因为Leave()调用Release()和Release()是虚拟的-向AV保证调用带有NIL引用的虚拟方法(Enter()的同上调用了虚拟Acquire()方法)。

在任何情况下:

最坏的情况:异常(exception)或奇怪的行为

“最佳”情况:拥有线程似乎认为它正常地“离开”了该部分。

在任何情况下,死锁或挂起都不会仅仅是由于某个线程中的某个关键部分被释放而相对于其他线程随后尝试进入或离开该关键部分的结果而导致。

所有这些都是一种反复无常的说法,听起来您的线程代码中有一个更基本的竞争条件,而这与关键部分的释放没有直接关系。

无论如何,我希望我的一点点调查工作可以使您走上正确的道路。

关于multithreading - 为什么我的多线程应用程序关闭时有时会挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4559234/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com