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

Multi-threading...

21 views
Skip to first unread message

Carl Danley

unread,
Jul 20, 2008, 1:38:31 AM7/20/08
to
Alright so... I am running into a problem that is holding me back from
writing the rest of my application. I have tried to find information on this
error but it seems that I cannnot. Im making something like this:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
HANDLE ThreadA, ThreadB;
//---------------------------------------------------------------------------
DWORD WINAPI Thread1(LPVOID Param);
DWORD WINAPI Thread2(LPVOID Param);
//---------------------------------------------------------------------------
DWORD WINAPI Thread2(LPVOID Param)
{
//code here
ShowMessage("test2");
//terminate Thread
TerminateThread(Thread, false);
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI Thread1(LPVOID Param)
{
//code here
ShowMessage("test");
//terminatethread
TerminateThread(Thread, false);
return 0;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//initialize the thread
DWORD Id;
Thread = CreateThread(0, 0, ThreadA, Form1->Handle, CREATE_SUSPENDED, &Id);
ResumeThread(Thread);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//initialize the thread
DWORD Id;
Thread = CreateThread(0, 0, ThreadB, Form1->Handle, CREATE_SUSPENDED, &Id);
ResumeThread(Thread);
}
//---------------------------------------------------------------------------

For example, all of my FTP work would be done in Thread1 and the Algorithm
to deal with the files downloaded and populate a component that shows the
users info on the latest applications would be done in Thread2. Here is my
problem: When I actually add the full implementation into these threads,
they crash the program on exit. What am I doing wrong? Is there some site
for BCB that can help me? I just need to see an example of how a fully
thread, working application works... The compiler error I get is Error 1400:
Invalid Window Handle... I have had other people test this and yet it doesnt
work on their end either... I have been pulling my hair for about a week...
Any help would be greatly appreciated, as i'm trying to push this
application out as an Alpha version in the next 2 weeks...

Bob Gonder

unread,
Jul 20, 2008, 1:02:49 PM7/20/08
to
Carl Danley wrote:

>DWORD WINAPI Thread2(LPVOID Param)
>{
> //code here
> ShowMessage("test2");
> //terminate Thread
> TerminateThread(Thread, false);
> return 0;
>}

<Help>
TerminateThread is a dangerous function that should
only be used in the most extreme cases.</Help>

TerminateThread is used OUTSIDE the thread to terminate it with prejudice.
You should never ever use it inside the thread.
ExitThread() or just plain return 0 are sufficient.

> Thread = CreateThread(0, 0, ThreadA, Form1->Handle, CREATE_SUSPENDED, &Id);

The error you are getting is from the threads having
the Form1 handle, but Form1 going away before they do.
Your Form1 should be waiting for these threads
to terminate before self destructing.

BOOL Terminating;

void SomeStartupFunc(void)
{
Terminating = FALSE;
Thread1 = CreateThread(...);
Thread2 = CreateThread(...);
}
void _fastcall Form1::OnClose(...)
{
Terminating = TRUE;
if( WAIT_FAILED == WaitforSingleObject(Thread1,2000) )
TerminateThread(Thread1,0);
CloseHandle(Thread1);
if( WAIT_FAILED == WaitforSingleObject(Thread2,100) )
TerminateThread(Thread2,0);
CloseHandle(Thread2);
}
DWORD Thread1(...)
{
while( ! Terminating )
{
};
{ Close any open resources. };
return 0;
}
The trick then comes in the thread.
It must not be in a hard-wait.
If it is in a wait, it can be perhaps up
to half of the 2000 specified in the OnClose.

Another trick, is if the thread is using WaitFor...()
you can CreateEvent and have the thread
WaitForMultipleObjects, including the new event.

BOOL Terminating;
HANDLE TerminatingEvent;

void SomeStartupFunc(void)
{
Terminating = FALSE;
TerminatingEvent = CreateEvent(0,TRUE,FALSE,NULL);
Thread1 = CreateThread(...);
Thread2 = CreateThread(...);
}
void _fastcall Form1::OnClose(...)
{
Terminating = TRUE;
SetEvent(TerminatingEvent);
if( WAIT_FAILED == WaitforSingleObject(Thread1,2000) )
TerminateThread(Thread1,0);
CloseHandle(Thread1);
if( WAIT_FAILED == WaitforSingleObject(Thread2,100) )
TerminateThread(Thread2,0);
CloseHandle(Thread2);
CloseHandle(TerminatingEvent);
}
DWORD Thread1(...)
{
while( ! Terminating )
{ HANDLE WaitHandles[2];
WaitHandle[0] = whatever I'm waiting for;
WaitHandle[1] = TerminatingEvent;
if( WaitForMultipleObjects( 2, WaitHandles,FALSE,INFINITE)
== WAIT_OBJECT_0 )
{ Handle whatever I'm supposed to be doing }
};
{ Close any open resources. };
return 0;
}


Carl Danley

unread,
Jul 20, 2008, 2:00:34 PM7/20/08
to
Alright, one more question I have... Every time a user clicks my 'Check for
Updates' button, it creates the thread that does the checking... Should I
recreate that threat everytime the button is clicked, like so:

BiBtn1->OnClick() :
{
DWORD Id;
Thread = CreateThread(.....);
ResumeThread(Thread);
}

Will this cause any errors, or can i just recreate it everytime the button
is clicked? If it does create errors, is there anyway that I can have the
thread Resume and startover?

"Bob Gonder" <no...@nowhere.invalid> wrote in message
news:g8o684tvboeu25bfo...@4ax.com...

Carl Danley

unread,
Jul 20, 2008, 4:13:34 PM7/20/08
to
One more thing... Is it better to use Application->Handle rather than
Form1->Handle... where it automatically taken care of?

Bob Gonder

unread,
Jul 20, 2008, 4:31:20 PM7/20/08
to
Carl Danley wrote:

>Alright, one more question I have... Every time a user clicks my 'Check for
>Updates' button, it creates the thread that does the checking... Should I
>recreate that threat everytime the button is clicked, like so:

I doubt they will be clicking regularly, so, yes
one click -> one thread seems reasonable.
But, I think if the user is capable of click-click-click-clicking
your button, it might cause some problems.
Ways to get around that:

Option 1: Use a mutex within the thread so if it is started
while the mutex is active (prior thread still running),
it will simply return.

Option 2: Set a global BOOL and check it in the OnClick.
OnClick()
{ if( ! Downloading )
{ CloseHandle(CreateThread());
} }
Thread()
{ Downloading = TRUE;
{do the download}
Downloading = FALSE;
}

Option 3: Disable the button.
Button1::OnClick()
{ Button1->Enabled = FALSE;
CloseHandle(CreateThread());
}
Thread()
{
{download}
Button1->Enabled = TRUE;
}

Problem is in remembering to close the handle, and
having the handle available for waiting in the OnClose()

Something else you could do...
Have the OnClose set the global terminating
flag and then exit (no waiting for the threads).
Have the thread check the flag each time it
tries to use the window handle (ignore GUI if terminating).

if( ! Terminating )
Button1->Enabled = TRUE;


Bob Gonder

unread,
Jul 20, 2008, 10:12:08 PM7/20/08
to
Carl Danley wrote:

>One more thing... Is it better to use Application->Handle rather than
>Form1->Handle... where it automatically taken care of?

You never showed what you did with the
handle in the thread, so I have no idea.

As to if it will change the original bug, no.
The application is free to exit leaving the
threads running.


Remy Lebeau (TeamB)

unread,
Jul 21, 2008, 2:22:06 AM7/21/08
to

"Carl Danley" <cda...@codebyter.com> wrote in message
news:4882cf55$1...@newsgroups.borland.com...

> HANDLE ThreadA, ThreadB;

> ShowMessage("test2");

ShowMessage() is not thread-safe. Do not use it outside of the main thread.

> //terminate Thread
> TerminateThread(Thread, false);

Use ExitThread() instead. Or just exit from the function normally. The OS
will call ExitThread() for you.

> //initialize the thread
> DWORD Id;
> Thread = CreateThread(0, 0, ThreadA, Form1->Handle, CREATE_SUSPENDED,
> &Id);

You are calling CreateThread() wrong. It should look more like this:

ThreadA = CreateThread(NULL, 0, &Thread1, NULL, CREATE_SUSPENDED, &Id);

> ResumeThread(Thread);

If you are going to call ResumeThread() right away, then there is no point
in specifying the CREATE_SUSPENDED flag.

> When I actually add the full implementation into these threads, they crash
> the program on exit.

Please show the actual implementation.

> What am I doing wrong?

You haven't shown enough code to diagnose that.

> The compiler error I get is Error 1400: Invalid Window Handle...

At which point in your code? What does it look like?


Gambit


0 new messages