Solved

Create a Thread that you can send values with.

Posted on 2010-09-03
23
488 Views
Last Modified: 2012-06-21
Hi, is it possible to create a thread that you can send values with.

because I'm wanting to have about 5++ threads open at the same time updating different things within the listview at the same time. and it doesn't have to be restricted to the listview, it can be updating into a memo, though without freezing up the app.

is it possible? if so could anyone provide links/examples/functions/files etc. if you've created it in delphi, would u provide the pas and dfm.
0
Comment
Question by:eNarc
  • 9
  • 5
  • 4
  • +2
23 Comments
 
LVL 25

Accepted Solution

by:
epasquier earned 100 total points
ID: 33597110
each thread accessing VCL would have to synchronize with the main thread. Synchronization is the fact that 2 threads will lock one another while one is accessing shared data, so that no 2 threads read/write the same data at the same time, thus causing all sorts of errors.

This can be done with messages : all threads posting data to update to main thread which is then the only one to access the VCL components.

but Delphi has a convenient way of synchronizing without needing to handle all kinds of thread messages : it's the Synchronize feature.

basically, you just add Synchronize( )  around a procedure call in your thread, and this procedure will be the one accessing VCL. This procedure will be executed BY THE MAIN THREAD, and your origin thread is suspended until it's done.

Ex :

procedure TMyThread.UpdateVCL;
begin
 frmMain.ListBox.Items.Add(NewValue);
end;

procedure TMyThread.AddValue(aValue:String);
begin
 NewValue:=aValue; // New Value is a global or public property of TMyThread
 Synchronize(UpdateVCL);
end;

It is even probable that the synchronized procedure can have parameters, therefore removing the need to pass parameters as globals/public properties. I just haven't played enough, nor gone too deep in the Delphi code to be sure.
0
 
LVL 5

Author Comment

by:eNarc
ID: 33597298
where does the NewValue come from and how can I send it?
0
 
LVL 5

Author Comment

by:eNarc
ID: 33597403
getting errors not recognized.
0
 
LVL 32

Assisted Solution

by:ewangoya
ewangoya earned 100 total points
ID: 33597474
Heres an exmple epanding on epasquires comment

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyProcedure = procedure(const AValue: string) of object;

  TMyThread = class(TThread)
  private
    FValue: string;
    FMyProc: TMyProcedure;
    procedure DoProc;
  public
    constructor Create(AProc: TMyProcedure);
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    procedure UpdateList(const AValue: string);
    procedure UpdateMemo(const AValue: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyThread.Create(UpdateList);
  TMyThread.Create(UpdateMemo);
end;

{ TMyThread }

constructor TMyThread.Create(AProc: TMyProcedure);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  FMyProc := AProc;
  Resume;
end;

procedure TMyThread.DoProc;
begin
  if Assigned(FMyProc) then
    FMyProc(FValue);
end;

procedure TMyThread.Execute;
var
  I: Integer;
begin
  for I := 1 to 10 do
  begin
    FValue := IntToStr(I);
    Synchronize(DoProc);
    sleep(1000);
  end;
end;

procedure TForm1.UpdateList(const AValue: string);
begin
  ListBox1.Items.Add(AValue)
end;

procedure TForm1.UpdateMemo(const AValue: string);
begin
  Memo1.Lines.Add(AValue);
end;

end.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33597486
of course you have to declare it. But ok, try calling the synchronized procedure with parameters. I really think it will work, I just don't remember and don't have time opening a project to test it.
procedure TMyThread.UpdateVCL(aValue:String);

begin

 frmMain.ListBox.Items.Add(aValue);

end;



procedure TMyThread.AddValue(aValue:String);

begin

 Synchronize(UpdateVCL(aValue));

end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 33597501
of course this is just a sample, you don't have to duplicate each such methods and usually will call directly Synchronize(Something) in your Execute function
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 33597541
@epasquire

Synchronize does not work with parameters
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33597688
yeah, I wasn't too sure about it. I KNOW I've seen it in some post, but never tested, maybe it was just a simplification to better explain an algo without too much getting into details.

But really, if you think how Synchronize works (it post a message with the object of the method called, and the address of the method - then the main thread use these info to make the call and return a message to say it's done) it could also add the parameters to the message. So I wouldn't bet it is impossible and maybe some Delphi versions can do it (or will)
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 33597751
I've been waiting for that functionality for a very long time. It would surely simplify alot of code. I'm not sure why its never been implemented.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 33598022
From D2009 onwards you can pass an anonymous method to Synchronize, thus eliminating the need for a global variable
0
 
LVL 5

Author Comment

by:eNarc
ID: 33600879
any examples/links/pas&dfm of it working would be great.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 5

Author Comment

by:eNarc
ID: 33600911
you know how you can pass things through with a function, though in a function you have to wait until it ends, to begin another.

same thing though able to open and close on its own. with like 5++ running at the same time. and able to pass info through it so it does its job.
0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 300 total points
ID: 33605656
there is also a delphi article which passes values back through a callback procedure
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/A_239-Displaying-progress-in-the-main-form-from-a-thread-in-Delphi.html

the callback gets called from the synchronized method
it's up to the owner of the callback what to do with the information
it's not up to the thread

it's a common mistake to update vcl objects from within the thread
it makes the threads dependant on the form
this should not be the case

if you have to use "uses MainForm" in your thread, then that's using the thread to update the mainform
0
 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 33609183
if you want different threads to post data back to the vcl
you could use a intermediate thread which channels all this data
there will allways be a bottleneck if you need to go from a multiple to a single

the threads posting to the intermediate thread would not have to wait for vcl
but they would have to wait on the sync object to add data in intermediate thread
this can cause a problem if the secondary threads can produce data faster than the intermediate thread can process
0
 
LVL 5

Author Comment

by:eNarc
ID: 33612167
Thanks aikimark makes more sense now hehe :P
0
 
LVL 5

Author Comment

by:eNarc
ID: 33612173
http:#33609183 Geert_Gruwez

mostly I'm after a function that u can send and it doesn't have to wait for it to end before activating another function.
0
 
LVL 5

Author Comment

by:eNarc
ID: 33612223
at the moment I'm using simply this to do the task, though its just on 1 thing.



procedure TForm1.ListView1Edited(Sender: TObject; Item: TListItem; var S: string);
procedure SaveThread(use : Pointer) ;
begin
  sleep(100);
  Save;
end;
var
  Thid:dword;
begin
  CreateThread(nil, 0, @SaveThread, nil, 0, thid);
end;


though I just can't send anything with it, it does 1 task and 1 task alone. only reason why I use the above is because when editing the listview, it would load the save before actually applying the edit to the listview, so sending it in a thread so it detaches from the procedure, and then within 100 it will then begin the save, saying the edit properly.

though really I'd like a function that I can send that is independent of the procedure once activated, than waiting for that to finish before beginning the next......
0
 
LVL 5

Author Comment

by:eNarc
ID: 33612232
why isn't independent functions/procedures standard? cos it seems like everyone would have a use for it.
0
 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 33615268
well ... ugh ... not waiting .. but you are using sleep ???
what is that good for ?

you will need to elaborate
and post a snippet of inside your thread

is the thread you want to send info back from
or do you just want to launch a thread
or do you want to put something on a queue for a thread to proces ?
0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 300 total points
ID: 33615469
if you want to know about threads:

check the site for omnithread of the DelphiGeek
http://www.thedelphigeek.com/

and specific for his threading:
http://www.thedelphigeek.com/search/label/OmniThreadLibrary
0
 
LVL 5

Author Comment

by:eNarc
ID: 33616475
http:#33615268 Geert_Gruwez

>>well ... ugh ... not waiting .. but you are using sleep ???
sleeped to give the listview time to apply the edit, before saving, test it for yourself with listview and editing the caption when you click on it and then press enter, it runs the edit before it applys the edit, making the edit useless., it should be called BeforeEdit... than Edit...

>>what is that good for ?
absolutely everything.

>>you will need to elaborate
in what way?

>>and post a snippet of inside your thread
regardless of the snippet inside the thread, merely allowing a function to work independently from that of the executioner..


so for example with a procedure like so
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
for i:= 0 to listview1.items.count - 1 do//5 items
  Search(listview1.items[i].caption,*.*',listview1.items[i]);//'C:\
//  Search(,*.txt');//'E:\'
//  Search(,*.dfm');//'F:\'
//  Search(',*.pas');//'G:\
//  Search(',*.exe');//'H:\

end;

and boom, it activates all 5 at once allowing for individual updating and searching of all hard drives at once, this is just 1 useful way of using it.

>>is the thread you want to send info back from
sending information back isn't really important as it will execute independently of what started it making it impossible to return a result.

>>or do you just want to launch a thread
yea, executing it and allowing it to do its thing in its own time separate from what called it. so the application doesn't have to wait for it to finish, it can execute it and then have that running in the background while the application is free to do other useful things.

>>or do you want to put something on a queue for a thread to proces ?
a queue would be handy at times, like for example you only wanting to activate 5 threads though u have 10 threads being activated, queuing those extra 5 would be great.


0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 300 total points
ID: 33616787
you are indeed looking for a queued system
the delphi geek has actually the state of the art what you are looking for

i have to admit, it is complex
he has posted a webinar about it
http://video.vdug.org/2010/July/OmniThread%20Library_controller.swf

you might want to check the indy code for the threading
also a very extensive resource

because of this complexity i created my own system (less complex, and a lot less functionality)
it's a basic threading system
check this question:
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26193383.html
and bugfix:
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26193383.html#32794882

the basics for working with threads are:
1: start the thread in the vcl and give it a handle to post info back to a processing system
2: give the thread *everything* it needs to do it's job, without the need for other VCL object interaction
 * 3: if you can't do it with item 2, then use syncro objects to access all the shared resources
4: if necessary let the thread post back information (and don't update any vcl objects from within the thread)
5: if you receive loads of info from multiple threads, summarize first and then update the vcl
6: build in a cancel or kill for the thread so you can instantly close app, otherwise display the closing progress to the user
7: keep in mind, programming with threads is not easy, debugging is even more complex
8: provide a message file logging which you can switch on and off inside the threads/app
 
so in your case
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
for i:= 0 to listview1.items.count - 1 do//5 items
  Search(listview1.items[i].caption,*.*',listview1.items[i]);//'C:\
//  Search(,*.txt');//'E:\'
//  Search(,*.dfm');//'F:\'
//  Search(',*.pas');//'G:\
//  Search(',*.exe');//'H:\
end;

the thread searches the files, and then gathers all the info in a thread local variable (a stringlist ?)
when finished it then sends a message to the message processing procedure with the results
in the processing procedure you can then gather all needed info about the results
and if this procedure is synchronized, update the listview (using beginupdate and endupdate)

it's basically what that question is about
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now