我正在尝试通过多个线程来处理类型为array of record
的变量,并且不确定执行的方法是否正确,或者是否有更好更好的方法?
我声明了一个boolean
变量作为锁,当某个线程想要访问该数组时,它将等待直到锁被关闭,然后激活该锁,完成后,对其进行解锁并让其他人可以访问。
此代码在实施部分中声明
...
implementation
var Data : array of TData;
var Data_Lock:Boolean=false;
procedure Lock_Data();
begin
while Data_Lock = True do
sleep(1);
Data_Lock := True;
end;
procedure UnLock_Data();
begin
Data_Lock := False;
end;
procedure ClearAll();
begin
Lock_Data();
SetLength( Data, 0 );
UnLock_Data();
end;
....
整个项目仍未完成。现在看来这行得通,但是我对这些东西如何在核心工作还一无所知,如果两个线程恰好同时启动是否会出现问题?
答案 0 :(得分:5)
您的锁定方法不是线程安全的,并且不会保护您的数据。
对于多个线程,您必须考虑到任何特定线程的执行都可以随时中断,并且另一个线程可以“跳转”并在它们之间访问某些变量。
这意味着可能出现以下情况(简化):
Data_Lock is False
Thread A enters Lock_Data()
Thread A checks Data_Lock -> False and skips the loop
Thread B enters Lock_Data()
Thread B checks Data_Lock -> False and skips the loop (Thread A didn't have the chance to set it to True yet)
Thread A continues -> sets Data_Lock to True and gains access to protected data
Thread B continues -> sets Data_lock to True and gains access to protected data while Thread A is still using that data
您可以改用TCriticalSection
中的System.SyncObjs
。
var DataLock: TCriticalSection;
procedure ClearAll();
begin
DataLock.Enter;
try
SetLength(Data, 0);
finally
DataLock.Leave;
end;
end;
由于TCriticalSection
是一个类,因此您需要先创建DataLock
实例,然后才能使用它,并且在不再需要它时需要释放它。例如,您可以在单元的初始化/完成部分中进行此操作。
initialization
DataLock := TCriticalSection.Create;
finalization
DataLock.Free;
end.
但是,更好的方法是将数据和关键部分包装在一个类中。