Create a Thread that you can send values with.

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.
LVL 5
eNarcAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Emmanuel PASQUIERFreelance Project ManagerCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
eNarcAuthor Commented:
where does the NewValue come from and how can I send it?
0
eNarcAuthor Commented:
getting errors not recognized.
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

Ephraim WangoyaCommented:
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
Emmanuel PASQUIERFreelance Project ManagerCommented:
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
Emmanuel PASQUIERFreelance Project ManagerCommented:
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
Ephraim WangoyaCommented:
@epasquire

Synchronize does not work with parameters
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
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
Ephraim WangoyaCommented:
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
DragonSlayerCommented:
From D2009 onwards you can pass an anonymous method to Synchronize, thus eliminating the need for a global variable
0
eNarcAuthor Commented:
any examples/links/pas&dfm of it working would be great.
0
eNarcAuthor Commented:
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
Geert GOracle dbaCommented:
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
Geert GOracle dbaCommented:
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
eNarcAuthor Commented:
Thanks aikimark makes more sense now hehe :P
0
eNarcAuthor Commented:
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
eNarcAuthor Commented:
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
eNarcAuthor Commented:
why isn't independent functions/procedures standard? cos it seems like everyone would have a use for it.
0
Geert GOracle dbaCommented:
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
Geert GOracle dbaCommented:
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
eNarcAuthor Commented:
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
Geert GOracle dbaCommented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.