Synchronizing/sending data between threads

╄→尐↘猪︶ㄣ 提交于 2019-12-02 23:32:31

Synchronize is specifically designed to execute code in the main thread; that's why it seems to lock everything up.

You can use several ways to communicate from the worker threads to the boss thread:

  • Add a callback to each worker thread, and assign it from the boss thread when it's created. It can pass back whatever as parameters, along with a thread ID or some other identifier.

  • Post a message from the worker thread to the boss thread using PostThreadMessage. The disadvantage here is that the boss thread has to have a window handle (see Classes.AllocateHWnd in the Delphi help and David Heffernan's comment below).

  • Use a good quality third-party threading library. See OmniThreadLibrary - it's free, OS, and extremely well written.

My choice would be the third. Primoz has done all the hard work for you. :)

After your comment, here's something along the lines of my first suggestion. Note that this is untested, since writing the code for a TBoss and TWorker thread + a test app is a little long for the time I have right this minute... It should be enough to give you the gist, I hope.

type 
  TWorker = class(TThread) 
  private 
    fResult : TResultRecord;
    fListIndex: Integer;
    procedure SetOnSendResult(const Value: TNotifyEvent);
    ....
    ....
  public
    property OnSendResult: TNotifyEvent write SetOnSendResult; 
    property Result : TResultRecord read fResult;
    property ListIndex: Integer read FListIndex write FListIndex;
    ....
  end;

type 
  TBoss=class(TThread)
  private
    FWorkerList: TThreadList; // Create in TBoss.Create, free in TBoss.Free
    ...
  end;

procedure TWorker.SendBossResults; 
begin 
  if not Terminated then
    SendResult; 
end;

procedure TBoss.ProcessWorkerResults(Sender: TObject); 
var
  i: Integer;
begin 
  if not terminated then 
  begin 
    If TWorker(Sender).Result.HasRecord then
    begin
      FWorkerList.LockList;
      try
        i := TWorker(Sender).ListIndex;
        // Update the appropriate record in the WorkerList
        TResultRecord(FWorkerList[i]).Whatever...
      finally
        FWorkerList.UnlockList;
      end;
    end;
  end; 
end;
Daniele Teti

You could use a thread safe queue. In DelphiXE there is the TThreadedQueue. If you don't have DXE, try OmniThreadLibray - this library is very good for all threading issues.

As I mentioned new options in Delphi 2009 and higher, here is a link to an example for Producer / Consumer communication between threads, based on the new objct locks, in my blog:

Thread Synchronization with Guarded Blocks in Delphi

In a note regarding the deprecated methods TThread.Suspend and TThread.Resume, The Embarcadero DocWiki for Delphi recommends that “thread synchronization techniques should be based on SyncObjs.TEvent and SyncObjs.TMutex.“ There is, however, another synchronization class available since Delphi 2009: TMonitor. It uses the object lock which has been introduced in this version ...

Emi

public properties of the TWorker class MUST have get and set methods, so you can use a Tcriticalsection to give the values of the properties. Otherwise, you´d be having thread-safe issues. Your example seems ok, but in the real world, with thousands of threads accessing to the same value would result in an read error. Use critical sections.. and you wouldn´t have to use any Synchronize. This way you avoid going to the message queues of windows and improve performance. Besides, if you use this code in a windows service app, (where windows messages aren´t allowed), this example wouldn´t work. The synchronize method doesn´t work unless there´s access to the windows message queue.

Solved!! (answer taken from the question)
The fixes made for this problem where two fold.
First remove the syncronization call in the TWorker SendBossResult method.

Second add a fProcessWorkerResult CritialSection to TBoss class. Create and Free this in create/destroy of the TBoss. In the ProcessWorkerResults method call fProcessWorkerResult.Enter and fProcessWorkerResult.leave around the code which needs to be safe from multiple worker results streaming in.

The above was the conclusion after Kens code and follow up comment. Many thanks kind sir, hats off to you!.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!