从其他线程访问VT数据是否安全? [英] Is it safe to access VT data from the other thread?
问题描述
从辅助线程更改VirtualTreeView数据是否安全? 如果是的话,我应该使用关键部分(甚至是同步方法)吗?
Is it safe to change VirtualTreeView data from the secondary thread ? And if yes, should I use critical sections (or even Synchronize method) ?
恐怕当我要从另一个线程写入VT的数据记录时,主线程会同时调用其重绘,并且此刷新将导致一次读取同一记录.我会补充一下,我在应用程序中仅使用2个线程.
I'm afraid that when I'll be writing to the VT's data record from the other thread, main thread invokes its repaint meanwhile and this refresh will cause reading of the same record at one time. I would supplement I'm using only 2 threads in the application.
类似...
type
PSomeRecord = ^TSomeRecord;
TSomeRecord = record
SomeString: string;
SomeInteger: integer;
SomeBoolean: boolean;
end;
...
var FCriticalSection: TRTLCriticalSection; // global for both classes
...
procedure TMyCreatedThread.WriteTheTreeData;
var CurrentData: PSomeRecord;
begin
EnterCriticalSection(FCriticalSection); // I want to protect only the record
CurrentData := MainForm.VST.GetNodeData(MainForm.VST.TopNode);
with CurrentData^ do // I know, the ^ is not necessary but I like it :)
begin
SomeString := 'Is this safe ? What if VT will want this data too ?';
SomeInteger := 777;
SomeBoolean := True;
end;
LeaveCriticalSection(FCriticalSection);
MainForm.VST.Invalidate;
end;
// at the same time in the main thread VT needs to get text from the same data
// is it safe to do it this way ?
procedure TMainForm.VST_GetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var CurrentData: PSomeRecord;
begin
EnterCriticalSection(FCriticalSection); // I want to protect only the record
CurrentData := VST.GetNodeData(VST.TopNode);
with CurrentData^ do
begin
case Column of
0: CellText := SomeString;
1: CellText := IntToStr(SomeInteger);
2: CellText := BoolToStr(SomeBoolean);
end;
end;
LeaveCriticalSection(FCriticalSection);
end;
// I'm afraid the concurrent field reading may happen only here with the private VT fields
// FNodeDataSize, FRoot and FTotalInternalDataSize, since I have Node.Data locked by the
// critical sections in the VT events, some of those may be accessed when VT is refreshed
// somehow
function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
begin
Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
Result := nil
else
Result := PByte(@Node.Data) + FTotalInternalDataSize;
end;
更新
我已经在代码中添加了关键部分,即使此函数仅返回指向记录的指针,从TMyCreatedThread类调用GetNodeData真的不安全吗?
I've added the critical sections to the code, is it really unsafe to call GetNodeData from TMyCreatedThread class, even if this function only returns a pointer to the record ?
非常感谢
致谢
推荐答案
不,特别是您的操作方式.
No, especially the way you're doing it.
VST
是可视控件.直接从线程中引用的MainForm
也是如此. GUI控件不是线程安全的,因此不应直接从线程访问.另外,您是从线程中引用全局变量"MainForm".这绝对不是线程安全的.
VST
is a visual control. So is MainForm
, which you're referring to directly from your thread. GUI controls are not thread-safe, and shouldn't be accessed directly from a thread. In addition, you're referring to the global variable 'MainForm' from the thread. This is absolutely NOT thread-safe.
如果需要从主窗体和单独的线程访问VST
的数据,请不要将其直接存储在VST.Node.Data
中.将其保留在外部列表中,您可以使用关键部分或某些其他线程安全的方法将其包围,并在线程中访问该外部列表(首先锁定它)或在VST
事件中访问主列表.有关可锁定列表的示例,请参见Delphi RTL中的TLockList
;有关示例同步类的信息,请参见TMultipleReadExclusiveWrite
.
If you need to access the data for the VST
from both your main form and a separate thread, don't store it directly in VST.Node.Data
. Keep it in an external list that you can surround with a critical section or some other thread-safe method, and access that external list in the thread (locking it first) or your main form in the VST
events. See TLockList
in the Delphi RTL for an example of a lockable list, and TMultipleReadExclusiveWrite
for a sample synchronization class.
这篇关于从其他线程访问VT数据是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!