Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

mmm.. threads...

5 views
Skip to first unread message

Stephen

unread,
Dec 31, 2001, 4:28:51 AM12/31/01
to
**NOTE** I've got the blunt question right at the end of this message. Most
of this is just to give you an idea of what I've done, and need to do.

Over the last couple days, I've been attempting to write a word indexing
routine. So far, so VERY good. I can do an index compile of over 33,000
lines, and break it down to about 13,000 words, all in about 2 minutes time.
I can, from there, do an indexed search on any word or set of words, and get
ALL the results back in under 1/4 of a second.

I don't like my application freezing during that two minute run though...
So I thought about moving over to threads. I'm regretting the idea, but,
maybe theres a solution I'm just not grasping.

Problem is this...

I have a simple form, just until I can ~BEAUTIFY~ it. Just gives me the
basics. When I hit the button to regenerate the master database file, as
well as the indexes (For Letter, Words, and Word Length), the potential for
the user to hit that button to regenerate, WHILE its generating is there. I
want to disable it somehow.

Problems I'm running into... When I hit the regen button the first time,
the thread runs, and does what it needs to do. As I mentioned, if I hit the
button again, the app craps large, and I'm back to the drawing board.
Simple solution lead me to beleive that if I were to disable the button so
the user CAN'T hit the button again, I'd solve it all. Nope. I can disable
the button, but, as of yet, haven't figured out how to see if the thread is
still running. Checking to see if the objects got some kind of value other
than NIL (Button1.Enabled := Generator <> Nil) the button ALWAYS remains
disabled. (I'm doing this particular code in a timer).

So, I figured I'd try another way... If ya can't beat it.. Kill it, and
watch it die. pfft... Listen to that philosophy and ya got a long wait with
what I'm doin...

The thread is created within a component. The component is created at form
creation, and form destruction, so the question of the component not
existing is moot. The component has two interfaces. One is just to set a
variable within the component, and the other is to get the thread running.
Upon component creation, I have it set so that it creates the thread, but
doesn't execute it. So far so good. My train of thought is let the first
one die without doing anything, and get the second one to go.

So, at component creation, I've got the thread instantiated. Its there,
allocated, just not running. I hit the button on the form to get the ball
running. I put code in to DESTROY the thread, and then immediately recreate
it, and start it over again. Problem with this is that if I destroy the
thread while its running, the app craps. Thats logical. So, instead, I
changed Destroy to Terminate, then used the WaitFor method. It sits waits
there, and locks up the app. At least it doesn't puke like my other
methods.

So, here's what I need to accomplish...

*****

If you skipped all that above, in a short way of stating it, how do I get a
thread, which can run for MINUTES, get terminated, and restarted depending
on user interaction with a form? How can I see if a thread exists, is
running, or has run?

Thanks for ANY input, be it about threads, or, about another method to
implement thread behavior.

Stephen


Maarten Wiltink

unread,
Dec 31, 2001, 4:47:28 AM12/31/01
to
Stephen wrote in message <9dWX7.5355$AS4.7...@news20.bellglobal.com>...

>**NOTE** I've got the blunt question right at the end of this message.
Most
>of this is just to give you an idea of what I've done, and need to do.

<snip>

>I have a simple form, just until I can ~BEAUTIFY~ it. Just gives me the
>basics. When I hit the button to regenerate the master database file, as
>well as the indexes (For Letter, Words, and Word Length), the potential
for
>the user to hit that button to regenerate, WHILE its generating is there.
I
>want to disable it somehow.

Button.Enabled:=False; { really, that works }


>Problems I'm running into... When I hit the regen button the first time,
>the thread runs, and does what it needs to do. As I mentioned, if I hit
the
>button again, the app craps large, and I'm back to the drawing board.
>Simple solution lead me to beleive that if I were to disable the button so
>the user CAN'T hit the button again, I'd solve it all. Nope. I can
disable
>the button, but, as of yet, haven't figured out how to see if the thread
is
>still running. Checking to see if the objects got some kind of value
other
>than NIL (Button1.Enabled := Generator <> Nil) the button ALWAYS remains
>disabled. (I'm doing this particular code in a timer).

Are you clearing that variable when it's done? Doesn't sound like it.

<snip>

>*****
>
>If you skipped all that above, in a short way of stating it, how do I get
a
>thread, which can run for MINUTES, get terminated, and restarted depending
>on user interaction with a form? How can I see if a thread exists, is
>running, or has run?


Usually, by having it monitor some flags or other variables, which
can get set from the UI.

But once you're doing that, you can probably get it to work by
dispensing with the threads and just calling ProcessMessages once
in a while.

Groetjes,
Maarten Wiltink

Stephen

unread,
Dec 31, 2001, 5:07:36 PM12/31/01
to

"Maarten Wiltink" <maa...@kittensandcats.net> wrote in message
news:a0pc7i$r98$1...@news1.xs4all.nl...

> Stephen wrote in message <9dWX7.5355$AS4.7...@news20.bellglobal.com>...
> >**NOTE** I've got the blunt question right at the end of this message.
> Most
> >of this is just to give you an idea of what I've done, and need to do.
>
> <snip>
>
> >I have a simple form, just until I can ~BEAUTIFY~ it. Just gives me the
> >basics. When I hit the button to regenerate the master database file, as
> >well as the indexes (For Letter, Words, and Word Length), the potential
> for
> >the user to hit that button to regenerate, WHILE its generating is there.
> I
> >want to disable it somehow.
>
> Button.Enabled:=False; { really, that works }
>

Yes.. I know that REALLY works... But the trick is to get it re-enabled
AFTER the threads done, or has been terminated.

>
> >Problems I'm running into... When I hit the regen button the first time,
> >the thread runs, and does what it needs to do. As I mentioned, if I hit
> the
> >button again, the app craps large, and I'm back to the drawing board.
> >Simple solution lead me to beleive that if I were to disable the button
so
> >the user CAN'T hit the button again, I'd solve it all. Nope. I can
> disable
> >the button, but, as of yet, haven't figured out how to see if the thread
> is
> >still running. Checking to see if the objects got some kind of value
> other
> >than NIL (Button1.Enabled := Generator <> Nil) the button ALWAYS remains
> >disabled. (I'm doing this particular code in a timer).
>
> Are you clearing that variable when it's done? Doesn't sound like it.

I neglected to mention that the variable name Generator is the name of the
thread. (Generator:=TThread.create(False))

>
> <snip>
>
> >*****
> >
> >If you skipped all that above, in a short way of stating it, how do I get
> a
> >thread, which can run for MINUTES, get terminated, and restarted
depending
> >on user interaction with a form? How can I see if a thread exists, is
> >running, or has run?
>
>
> Usually, by having it monitor some flags or other variables, which
> can get set from the UI.
>
> But once you're doing that, you can probably get it to work by
> dispensing with the threads and just calling ProcessMessages once
> in a while.
>

I'm still not going to be able to capture other events, such as clicking. I
MAY be able to redraw the form with updated information as to the status of
the thread, and other misc information, but, the idea is to let the user
have control 100% of the time, or as close to it as possible. If the user
wants to make a modification, and regenerate the list again, its gotta be
there to do so.

Aaron Lawrence

unread,
Dec 31, 2001, 9:10:31 PM12/31/01
to
In article <yk5Y7.6004$AS4.1...@news20.bellglobal.com>,
idon...@somewhere.asdf says...

> Yes.. I know that REALLY works... But the trick is to get it re-enabled
> AFTER the threads done, or has been terminated.

Thread.Create...
Thread.Resume; // if you didn't start it on create

Thread.OnTerminate := MyTerminateMethod;

TMyForm.MyTerminateMethod;
begin
Button.Enable;
end;


--
aaronl at consultant dot com

Stephen

unread,
Jan 1, 2002, 6:31:43 AM1/1/02
to

"Aaron Lawrence" <aaro...@consultantSPAM.com> wrote in message
news:MPG.169bd3b49...@news.visp.co.nz...

> In article <yk5Y7.6004$AS4.1...@news20.bellglobal.com>,
> idon...@somewhere.asdf says...
> > Yes.. I know that REALLY works... But the trick is to get it re-enabled
> > AFTER the threads done, or has been terminated.
>
> Thread.Create...
> Thread.Resume; // if you didn't start it on create
>
> Thread.OnTerminate := MyTerminateMethod;

Wanna know the damnest thing about this line above? Doing a step trace,
after I set that method, it'd immediately jump right into the terminate
method. The thread had been created (Hasn't been started) but, it still
thought it was dead, or something.

>
> TMyForm.MyTerminateMethod;
> begin
> Button.Enable;
> end;
>

Also, another quirk... I had to make a plain procedure to get this one to
work. I couldn't use a form proc, or, a proc thats IN the thread class, or
anything. It had to be a PROCEDURE MYTERMINATETHREAD; BEGIN ... END;

Aaron Lawrence

unread,
Jan 1, 2002, 10:18:46 PM1/1/02
to
In article <t6hY7.6980$AS4.1...@news20.bellglobal.com>,
idon...@somewhere.asdf says...

> Wanna know the damnest thing about this line above? Doing a step trace,
> after I set that method, it'd immediately jump right into the terminate
> method. The thread had been created (Hasn't been started) but, it still
> thought it was dead, or something.

Hm. I've never seen this before. I suspect something odd is going on in
your thread.

>
> > TMyForm.MyTerminateMethod;
> > begin
> > Button.Enable;
> > end;
> >
>
> Also, another quirk... I had to make a plain procedure to get this one to
> work. I couldn't use a form proc, or, a proc thats IN the thread class, or
> anything. It had to be a PROCEDURE MYTERMINATETHREAD; BEGIN ... END;

That doesn't sound right. You must be doing something wrong. You need a
form event like this:


Procedure TMyForm.OnThreadTerminate( Sender: TObject );
begin
end;

you would see this if you read the help on TThread.OnTerminate.

Have you read the help?

Sergio

unread,
Jan 3, 2002, 9:05:55 AM1/3/02
to
Aaron Lawrence <aaro...@consultantSPAM.com> wrote in message news:<MPG.169d3534c...@news.visp.co.nz>...

Hi:

Do you know synchronize method?

I think you can do this:

type

TSomething = class(TThread)
private
{ Private declarations }
procedure UpdateForm;
procedure Begining;
procedure Ending;
protected
procedure Execute; override;
end;

implementation

uses UFormToBeUpdated; {VERY IMPORTANT: the form to be updated}

procedure TSomething.UpdateForm;
begin
FormToBeUpdated.Button1.enabled:= true;
end;

procedure TSomething.Begining;
begin
showmessage('My thread in begining')
end;

procedure TSomething.Ending;
begin
showmessage('My thread in deading')
end;

procedure TSomething.execute;
begin
synchrnize(Begining);
{ your code }

synchronize(Ending);
synchronize(UpdateForm);
FreeOnTerminate:= true;
end;

Probe it. It works.

By by.

Billy Bob

unread,
Jan 3, 2002, 9:36:21 AM1/3/02
to
On Mon, 31 Dec 2001 04:28:51 -0500, Tony wrote:

Lot's of ways of 'seeing' if the the thread is running. My favourite
is to attach the threaded component to a Progress Bar and then use the
synchronize method to call it's stepit routine. If you are not worried
about a visual indication then just set a property in the component.
However to kill the currently running index thread and then start a
new one with new parameters, you have got to wait for the current one
if it's running to terminate. I.e set the threads teminate property
and then in the loop's main thread check if has been set during each
iteration of the loop and act accordingly.
P.S. Why did you make the decision to create the thread at component
creation time, I would have done it in a method, setFreeOnTerminate to
true and then set the TMyThread Pointer in the component to Nil in the
OnTerminate Event, That way you know it's running because it's not
nil.

Sergio

unread,
Jan 3, 2002, 9:40:25 AM1/3/02
to
"Stephen" <idon...@somewhere.asdf> wrote in message news:<9dWX7.5355$AS4.7...@news20.bellglobal.com>...

Hi Stephen.

I think you can create the thread like this:

TSomeForm.Button11Click(Sender: TObject);
begin
SomeThread:= TSomeThread.create(false);
SomeThread.Priority := tpLowest;
end;

You can put your SomeThread variable in the "public" of your MainForm.

You could taste the thread state with then "Suspended" and "Terminated"
properties of the thread.

If you want your thread updates some form you need to use the "synchronize"
method of the thread.

Something like this:

TProcesoLibroDiario = class(TThread)
private
{ Private declarations }
procedure updateform;


protected
procedure Execute; override;
end;

implementation

uses Unitofformtobeupdated;

procedure TProcesoLibroDiario.updateform;
begin
if assigned(formtobeupdated) then
formtobeupdated.button1.enabled := false;
end;

procedure TProcesoLibroDiario.Execute;
begin
{Your code}
synchronize(updateform);
FreeOnTerminate:= true;
end;

end;

By.

Stephen

unread,
Jan 3, 2002, 6:40:43 PM1/3/02
to

"Aaron Lawrence" <aaro...@consultantSPAM.com> wrote in message
news:MPG.169d3534c...@news.visp.co.nz...

> In article <t6hY7.6980$AS4.1...@news20.bellglobal.com>,
> idon...@somewhere.asdf says...
> > Wanna know the damnest thing about this line above? Doing a step trace,
> > after I set that method, it'd immediately jump right into the terminate
> > method. The thread had been created (Hasn't been started) but, it still
> > thought it was dead, or something.
>
> Hm. I've never seen this before. I suspect something odd is going on in
> your thread.
>

Neither have I. The error I was getting was something along the line of
Incompatible Types. Cannot Assign a TNotifyEvent to something or other.
Delphi has been messing up today, and I've not rebooted, so, I can't get
more accurate.

> >
> > > TMyForm.MyTerminateMethod;
> > > begin
> > > Button.Enable;
> > > end;
> > >
> >
> > Also, another quirk... I had to make a plain procedure to get this one
to
> > work. I couldn't use a form proc, or, a proc thats IN the thread class,
or
> > anything. It had to be a PROCEDURE MYTERMINATETHREAD; BEGIN ... END;
> That doesn't sound right. You must be doing something wrong. You need a
> form event like this:
>

Ahhh.. gotta love having a computer thats so unique, it decides to make its
own rules for procedural calls and what not.

MOST of my problems are happening, when it comes to assigning events at run
time, happen either at compile time (By giving me a type missmatch) or at
run time (by running the terminate thread, just after I create it). Its
extremly odd behavior, and not logical to me, by far, but, I can't figure
out where this thing is screwing up.

>
> Procedure TMyForm.OnThreadTerminate( Sender: TObject );
> begin
> end;
>
> you would see this if you read the help on TThread.OnTerminate.
>

I see that with ANY component I add an event to. (Not to sound arogant or
upset with that statement.. Its just getting extremly frustrating) Thats
whats throwing me off. Everywhere else, I see the components event method
name put into the class header in the unit. But, I can't emulate the same
results at run time with my code. (Although, I just had a realization...
I'll fight with it later)

> Have you read the help?

over and over and over and over and over again. I've almost gotten to the
point where I'm thinking about putting a tthread component in the tool bar
and using it like I would a regular VCL. But then I might run into the
problem of being able to run that thread only once. (I've had bad luck
destroying/freeing a design time component at run time.

Stephen

unread,
Jan 3, 2002, 7:07:13 PM1/3/02
to

"Billy Bob" <billyBob...@Hotmail.com> wrote in message
news:3c346894...@news.easynews.com...

> On Mon, 31 Dec 2001 04:28:51 -0500, Tony wrote:
>
> Lot's of ways of 'seeing' if the the thread is running. My favourite
> is to attach the threaded component to a Progress Bar and then use the
> synchronize method to call it's stepit routine. If you are not worried
> about a visual indication then just set a property in the component.
> However to kill the currently running index thread and then start a
> new one with new parameters, you have got to wait for the current one
> if it's running to terminate. I.e set the threads teminate property
> and then in the loop's main thread check if has been set during each
> iteration of the loop and act accordingly.

So as everyone suggested in prior posts, do a check in the thread to see if
the threads property of Terminated is true. I've run the ideas through my
head a few times... Just a matter of finding the time to attempt the
corrections.

> P.S. Why did you make the decision to create the thread at component
> creation time, I would have done it in a method, setFreeOnTerminate to
> true and then set the TMyThread Pointer in the component to Nil in the
> OnTerminate Event, That way you know it's running because it's not
> nil.
>

I want a component who's soul purpose in life is to generate, and maintain
an indexed database of file names. The thread is created within the object,
and only run when specifically told to run. The components interface will
have additional methods to perform searches, available to the UI. Sketchy,
but heres what I wanted to do:

Form
- Locator (Empty class)
- Thread (TThread)
- CreateIndex (Method)
- Search (Method)

At form creation, approx 20 (maybe more if my theory works alright) Locator
objects will be created, each maintaining their own database of files.
These need to be created at the application start, because, if the database
is already existing on the HDD, then, no need to recreate it, so, the Search
method can just examine the stats. And if Search sees that the database
actually doesn't exist, it can start the CreateIndex thread, and let it
maintain itself. If the thread is running, Search will have a routine to
remember what additional lookups it needs to take care of, while the thread
is working away. Once Search sees that the thread has finished what it
needs to do, then, it will go through, and start pumping out the search
results back to the UI.

I thought about making one thread to do all the indexing, but, still, until
I try make the suggested modifications mentioned in this message thread, I'm
still up the creek about Search not knowing if its safe to do an actual
look-up.

As for you guys who are asking why not just use findfirst and skip the
indexing portion all together... Too slow.

This program is being designed for fastest access possible. To stress test
it, I have an IRC client sitting in a few large MP3 channels, and its
pumping information to the program to do searches, based on the users
@Locator/@Find requests. 11 chans, anywhere from 800 to 300 users, and
about 3/4 of these users are NORMALS (No special access, or regular users
doing searches)

The old methods I've been using, such as, using FINDFIRST for each search,
and reading through that 33,000 line database sequentially to find results,
failed. Too slow. The program would get behind, and the queue of messages
would end up just becoming too much to handle for the program. To do one
search took anywhere from one second to three seconds, depending on which
style of search, and the number of results reported back. In theory, why
should I look for that needle in the haystack, when I can increase the size
of the needle and reduce the size of the haystack with an indexed search?
(1 second per search versus 1/4 per search is very appitizing)


Martin Harvey

unread,
Jan 15, 2002, 9:07:20 PM1/15/02
to

See if the tutorial on my website gives you any ideas :-)

--
http://www.pergolesi.demon.co.uk
ICQ: 37298917

5468726565204F5327732066726F6D20636F72706F72617465206B696E677320696E
20746865697220746F77657273206F6620676C6173732C0D0A536576656E2066726F
6D2076616C6C6579206C6F726473207768657265206F726368617264732075736564
20746F2067726F772C0D0A4E696E652066726F6D20646F74636F6D7320646F6F6D65
6420746F206469652C0D0A4F6E652066726F6D20746865204461726B204C6F726420
4761746573206F6E20686973206461726B207468726F6E650D0A496E20746865204C
616E64206F66205265646D6F6E642077686572652074686520536861646F7773206C
69652E0D0A4F6E65204F5320746F2072756C65207468656D20616C6C2C206F6E6520
4F5320746F2066696E64207468656D2C0D0A4F6E65204F5320746F206272696E6720
7468656D20616C6C20616E6420696E20746865206461726B6E6573732062696E6420
7468656D2C0D0A496E20746865204C616E64206F66205265646D6F6E642077686572
652074686520536861646F7773206C69652E

Stephen

unread,
Jan 15, 2002, 10:29:13 PM1/15/02
to
Hey.. Thanks.. Reading over it right now.

"Martin Harvey" <mar...@pergolesi.demon.co.uk> wrote in message
news:3C44E058...@pergolesi.demon.co.uk...

0 new messages