TBackgroundWorker ReportFeedback function

Please post bug reports, feature requests, or any question regarding the DELPHI AREA projects here.

TBackgroundWorker ReportFeedback function

Postby smrwsmrw » December 5th, 2008, 9:16 pm

Hello, It seems that ReportFeedback can only return 2 integers(FeedbackID, FeedbackValue: Integer). If it could support return strings or objects, it would be very nice :D
for example when I use it to search file, I hope it could return the filename as feedfack
smrwsmrw
Member
Member
 
Posts: 4
Joined: August 27th, 2008, 12:00 am

Re: TBackgroundWorker ReportFeedback function

Postby Kambiz » December 6th, 2008, 1:07 pm

Hi,

It's not as easy as it seems, because events occur asynchronously.

When Worker.ReportFeedback method is called, the function returns immediately and the thread continues with the next statement. Later, at an unpredictable time, the OnWorkFeedback event occurs.

Even, if worker thread has a higher priority or has a small task to do, the OnWorkFeedback and OnWorkProgress events may occur when the thread is terminated and the task is completely done.

To see it in real, place a TBackgroundWorker and a TListBox on a form and write the following event handlers:

Code: Select all
procedure TForm1.FormCreate(Sender: TObject);
begin
  BackgroundWorker1.Execute;
end;

procedure TForm1.BackgroundWorker1Work(Worker: TBackgroundWorker);
var
  I: Integer;
begin
  for I := 1 to 999 do
  begin
    Worker.Tag := I;
    Worker.ReportFeedback(0, I);
  end;
end;

procedure TForm1.BackgroundWorker1WorkFeedback(Worker: TBackgroundWorker;
  FeedbackID, FeedbackValue: Integer);
begin
  ListBox1.Items.Add(Format('%d - %d', [FeedbackValue, Worker.Tag]));
end;


In the above code, the thread sets the Tag property of Worker to the loop variable and raises the OnWorkFeedback event by setting its FeedbackValue to the loop variable. Later, the OnWorkFeedback event handler shows the FeedbackValue and Worker's Tag property on the ListBox.

If OnWorkFeedback event was occurred synchronously, the Worker's Tag property was equal to FeedbackValue. However, as you can see, in an asynchronous call the result is unpredictable. In our example, all the OnFeedbackEvents are occurred when the thread was terminated because the Worker.Tag has a value of 999 for all feedback values.

Of course we can use an Event object to synchronize the thread with the OnWorkFeedback event handler. For this purpose, we add SyncObjs unit to the uses clause and declare an Event object. Here named SyncFeedback:

Code: Select all
uses
  SyncObjs;

var
  SyncFeedback: TEvent;


The Event object must be created and released, so we use OnFormCreate and OnFormDestroy event for this purpose:

Code: Select all
procedure TForm1.FormCreate(Sender: TObject);
begin
  SyncFeedback := TEvent.Create(nil, True, True, '');
  BackgroundWorker1.Execute;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(SyncFeedback);
end;


Then, we have to modify our OnWork event handler, so that after calling ReportFeedback, the thread waits for OnWorkFeedback event to occur:

Code: Select all
procedure TForm1.BackgroundWorker1Work(Worker: TBackgroundWorker);
var
  I: Integer;
begin
  for I := 1 to 999 do
  begin
    Worker.Tag := I;
    SyncFeedback.ResetEvent; // reset the event, we are going to wait for it to be set
    Worker.ReportFeedback(0, I);
    // some code that do not affect the synchronization can be here
    SyncFeedback.WaitFor(INFINITE); // wait for event to be set
  end;
end;


Then, in OnWorkFeedback event handler, we signal the Event object, so that the thread can continue its work:

Code: Select all
procedure TForm1.BackgroundWorker1WorkFeedback(Worker: TBackgroundWorker;
  FeedbackID, FeedbackValue: Integer);
begin
  ListBox1.Items.Add(Format('%d - %d', [FeedbackValue, Worker.Tag]));
  SyncFeedback.SetEvent; // set the event, so that thread continues
end;


Here is the complete code for the synchronization:

Code: Select all
uses
  SyncObjs;

var
  SyncFeedback: TEvent;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SyncFeedback := TEvent.Create(nil, True, True, '');
  BackgroundWorker1.Execute;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(SyncFeedback);
end;

procedure TForm1.BackgroundWorker1Work(Worker: TBackgroundWorker);
var
  I: Integer;
begin
  for I := 1 to 99 do
  begin
    Worker.Tag := I;
    SyncFeedback.ResetEvent; // reset the event, we are going to wait for it to be set
    Worker.ReportFeedback(0, I);
    // some code that do not affect the synchronization can be here
    SyncFeedback.WaitFor(INFINITE); // wait for event to be set
  end;
end;

procedure TForm1.BackgroundWorker1WorkFeedback(Worker: TBackgroundWorker;
  FeedbackID, FeedbackValue: Integer);
begin
  ListBox1.Items.Add(Format('%d - %d', [FeedbackValue, Worker.Tag]));
  SyncFeedback.SetEvent; // set the event, so that thread continues
end;


By running the new code, you will see Worker.Tag value is always equal to FeedbackValue, as expected.

When synchronization is involved, you can type cast a pointer or object to integer and pass it as FeedbackValue to the event handler.

In the next release of TBackgroundWorker, I will add some synchronization features to make these sort of tasks easier.

Besides using synchronization, there is other solution for sending strings, objects, or records to the main VCL thread. In this case, the worker thread sends a copy of string, object, or record to the OnWorkFeedback event handler. Later, the OnWorkFeedback event handler must release the allocated memory. Because the worker thread does not need to wait for the main VCL thread, this solution is preferred for threads with heavy works to do.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Re: TBackgroundWorker ReportFeedback function

Postby Kambiz » December 6th, 2008, 1:12 pm

BTW, maybe its better you use the TFindFile component.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Re: TBackgroundWorker ReportFeedback function

Postby Kambiz » December 6th, 2008, 6:20 pm

I released the new update. The new methods may make your coding a bit easier.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm


Return to DELPHI AREA Projects

Who is online

Users browsing this forum: No registered users and 3 guests

cron