我对正在分析的多线程应用程序有点迷茫。我认为我试图理解的函数在主线程中起作用。确保我在其中放置了进入和退出临界区代码。同样的临界区也用于程序启动(进入临界区)和终止(离开临界区)。
如我错了请纠正我。如果我的函数在主线程中起作用,则应允许进入临界区。但事实并非如此 - 我的功能只是在进入关键部分时停止。根据我的理解,这个函数在另一个线程中起作用。
我的方法对于理解哪个函数在哪个线程中起作用是否正确?
我对正在分析的多线程应用程序有点迷茫。我认为我试图理解的函数在主线程中起作用。确保我在其中放置了进入和退出临界区代码。同样的临界区也用于程序启动(进入临界区)和终止(离开临界区)。
如我错了请纠正我。如果我的函数在主线程中起作用,则应允许进入临界区。但事实并非如此 - 我的功能只是在进入关键部分时停止。根据我的理解,这个函数在另一个线程中起作用。
我的方法对于理解哪个函数在哪个线程中起作用是否正确?
只需使用调试器。在应用程序的启动代码或应用程序的任何消息处理程序中设置断点,并在调试器线程窗口中检查当前线程 ID。然后在相关函数中设置断点,并在执行到达该函数时检查线程 ID。如果它们不匹配,则不会在运行 UI 消息的同一线程上调用该函数。
当您在调试器中停止您的函数时,您可以查看调用堆栈窗口以查看导致您的函数调用的调用序列。这可以让您深入了解您是如何到达那里的,以及您是如何在不同的线程上到达那里的。
我相信您以错误的方式使用关键部分。想象一下,您有一个可能在主线程和其他线程中修改的变量。每次要访问此变量时,首先要访问Acquire
临界区;像这样:
if MyCriticalSection.TryEnter then // MyVariable is accessible
begin
MyVariable := MyVariable + 1;
MyCriticalSection.Release;
end
else begin
// do something useful and try again in a few milliseconds.
end;
请记住,当您调用 时Acquire
,调用线程将被冻结,直到临界区可用。因此,如果您Acquire
在应用程序的开头调用,第二次调用它会冻结您的主线程。
您不能将其锁定在主线程中。始终在线程中使用临界区。将 cs:TRTLCriticalSection 声明为全局变量。调用任何线程。在不在主线程中或不在线程中的创建构造函数中的执行过程中锁定和解锁 cs。
您也无法读取主线程内的 cnt 变量。但是 Synchronize 方法更新 mainCnt 变量以在主线程中读取它
var //global
cs :TRTLCriticalSection;
cnt:integer; //use it only inside thread
mainCnt:integer; //same value for cnt. use it inside a main thread.
///formcreate..
begin
InitializeCriticalSection(cs);
///formdestroy
DeleteCriticalSection(cs);
type
TThrInc = class(TThread)
private
fAnyParam:Integer;
protected
procedure Execute; override;
public
constructor Create(anyparam:integer);
end;
constructor TThrInc.Create(anyparam:integer);
begin
fAnyParam:=AnyParam; //you dont need this
end;
procedure TThrInc.execute;
var tmpcnt:integer;
begin
EnterCriticalSection(cs);
try begin
inc(cnt);
tmpcnt:=cnt;
end except end;
LeaveCriticalSection(cs);
Synchronize(
procedure
begin
mainCnt:=tmpcnt;
end);
end;