Is it safe to get VT data from another stream?

Is it safe to modify VirtualTreeView data from a secondary stream? And if so, should critical sections be used (or even the Synchronize method)?

I am afraid that when I write a record of VT data from another stream, the main stream causes it to be redrawn, and this update will cause the reading of the same record at a time. I would add that I use only 2 threads in the application.

Sort of...

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; 

Update

I have added critical sections to the code, is it really not safe to call GetNodeData from the TMyCreatedThread class, even if this function returns only a pointer to a record?

thanks a lot

Hello

+4
source share
1 answer

No, especially how you do it.

VST is a visual control. So, MainForm , which you are talking about directly from your thread. GUI elements are not thread safe and should not be accessible directly from the stream. In addition, you are referencing the MainForm global variable from the stream. This is absolutely NOT thread safe.

If you need to access data for VST both from the main form and from a separate stream, do not store it directly in VST.Node.Data . Store it in an external list that you can surround with a critical section or some other thread-safe method, and access this external list in a stream (first block it) or your main form in VST events. See TLockList in Delphi RTL for an example of a lockable list and TMultipleReadExclusiveWrite for a sample synchronization class.

+6
source

Source: https://habr.com/ru/post/1347160/


All Articles