BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Frames and terminating the threads that belong to them (BCB5

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Development)
View previous topic :: View next topic  
Author Message
Stephen R. Phillips
Guest





PostPosted: Fri Jul 22, 2005 2:33 pm    Post subject: Frames and terminating the threads that belong to them (BCB5 Reply with quote



I am attempting to figure out how to remove a thread object from a frame.
Is there any way to detect when a Frame is being removed or destroyed so I
can terminate the thread object in a sane orderly manner?
I cannot find anything close to the OnClose event for Forms in Frames.
Suggestions welcome!

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Fri Jul 22, 2005 5:56 pm    Post subject: Re: Frames and terminating the threads that belong to them ( Reply with quote




"Stephen R. Phillips" <cyberman_phillips (AT) yahoo (DOT) com> wrote


Quote:
Is there any way to detect when a Frame is being removed

Override the SetParent() method. From there, you can check for a NULL
pointer being assigned, or even if the parent is being changed to another
control.

Quote:
or destroyed

The destructor.


Gambit



Back to top
Stephen R. Phillips
Guest





PostPosted: Mon Jul 25, 2005 1:45 pm    Post subject: Re: Frames and terminating the threads that belong to them ( Reply with quote



"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in
news:42e13555$2 (AT) newsgroups (DOT) borland.com:

Quote:

or destroyed

The destructor.

Thanks this was a more graceful way of doing things for me at least.


I do have a problem (it always seems to be the case).
I cannot get my thread to execute.

I'm having the frame manage creating the nuking the thread and it is
passing messages to the thread for the Execute method. For some reason
firing messages to the thread does nothing. Here is most of the appropriate
code.
Header File
ScanView.h-----------------------------------------------------------------
//-------------------------------------------------------------------------
--


#ifndef ScanViewH
#define ScanViewH
//-------------------------------------------------------------------------
--
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include <ImgList.hpp>
#include <ToolWin.hpp>
#include <iostream.h>
#include <fstream.h>
//-------------------------------------------------------------------------
--
#include "PSX_Struct.h"
//-------------------------------------------------------------------------
--
#define THREADMSG_START_SCAN (WM_APP + 100)
#define THREADMSG_STOP_SCAN (WM_APP + 101)
#define THREADMSG_CONT_SCAN (WM_APP + 102)

//-------------------------------------------------------------------------
--
class TScan : public TThread
{
protected:
void __fastcall Execute();
private:
bool Scaning;

void ScanImage();

public:
int Position;
UINT8 *Sector;
UINT16 *PSXDISPLAY;
AnsiString Path;
bool Update;
TFrame *MyFrame;

TScan(bool);// : TThread(false);
//~Scan();
bool __fastcall Busy(void);
void __fastcall StartScan(void);
void __fastcall StopScan(void);
void __fastcall ContinueScan(void);

void __fastcall TerminateThread(TObject *);
};
//-------------------------------------------------------------------------
--

class TSCAN_FILE : public TFrame
{
__published: // IDE-managed Components
TPanel *SCAN_PNL;
TAnimate *SCAN_ANIM;
TTreeView *SCAN_TV;
TSplitter *SCAN_SPLIT;
TListView *SCAN_LV;
TImageList *SCAN_SIL;
TImageList *SCAN_LIL;
TImageList *SCAN_STATE;
TRadioGroup *SCAN_TYPE;
TPanel *SCAN_TB_PNL;
TToolBar *SCAN_TB;
TToolButton *SCAN_START;
TImageList *SCAN_TB_IL;
TToolButton *SCAN_STOP;
TToolButton *SCAN_TB_SEP1;
TImageList *SCAN_TV_IL;
void __fastcall SCAN_STARTClick(TObject *Sender);
void __fastcall SCAN_STOPClick(TObject *Sender);
private: // User declarations
TScan *Scanner;
public: // User declarations
int *Progress,
*MaxProg;
AnsiString Path;

__fastcall TSCAN_FILE(TComponent* Owner);
__fastcall ~TSCAN_FILE();
};
//-------------------------------------------------------------------------
--
extern PACKAGE TSCAN_FILE *SCAN_FILE;
//-------------------------------------------------------------------------
--
#endif
---------------------------------------------------------------------------

Main source code

ScanView.cpp---------------------------------------------------------------
//-------------------------------------------------------------------------
--

#include <vcl.h>
#pragma hdrstop

#include "ScanView.h"
#include "PSX_View.h"
#include "PSX_struct.h"
//-------------------------------------------------------------------------
--
#pragma package(smart_init)
#pragma resource "*.dfm"
TSCAN_FILE *SCAN_FILE;

//-------------------------------------------------------------------------
--
bool is_tim(UINT8 *);
bool is_tim_04(UINT8 *);
bool is_tim_08(UINT8 *);
bool is_tim_16(UINT8 *);
bool is_tim_24(UINT8 *);
//-------------------------------------------------------------------------
--
__fastcall TSCAN_FILE::TSCAN_FILE(TComponent* Owner)
: TFrame(Owner)
{
// you can't stop it if it's not scanning
SCAN_STOP->Enabled = false;
Scanner = new TScan(false);
Scanner->Position = 0;
Scanner->MyFrame = this;
}
//-------------------------------------------------------------------------
--
__fastcall TSCAN_FILE::~TSCAN_FILE()
{
int Index;
TControl *Ctrl;

for(Index = this->ControlCount -1; Index > -1; Index--)
{
// get the control
Ctrl = this->Controls[Index];
// remove the control
this->RemoveControl(Ctrl);
//delete the control
delete Ctrl;
}
// remove the scaner object
Scanner->TerminateThread(Scanner);
delete Scanner;
}
//-------------------------------------------------------------------------
--
void __fastcall TSCAN_FILE::SCAN_STARTClick(TObject *Sender)
{
if((Path.Length() > 0)&&
!Scanner->Busy())
{
// Start / Continue click
SCAN_ANIM->Active = true;
SCAN_STOP->Enabled = true;
SCAN_START->Enabled = false;
//Scanner->Terminated;
if(Scanner->Position > 0)
{
Scanner->ContinueScan();
}
else
Scanner->StartScan();
}
}
//-------------------------------------------------------------------------
--

void __fastcall TSCAN_FILE::SCAN_STOPClick(TObject *Sender)
{
if(Scanner->Busy())
{
// Pause/ Stop click
SCAN_ANIM->Active = false;
SCAN_STOP->Enabled = false;
SCAN_START->Enabled = true;
Scanner->StopScan();
}
}
//-------------------------------------------------------------------------
--
TScan::TScan(bool CreateSuspended) : TThread(CreateSuspended)
{
Sector = new UINT8[409600];
Terminated;
setmem(Sector, 0, 409600);
//this->OnTerminate = TerminateThread;
}
//-------------------------------------------------------------------------
--
bool __fastcall TScan::Busy(void)
{
Terminated;
return Scaning;
}
//-------------------------------------------------------------------------
--
void __fastcall TScan::Execute()
{
MSG msg;
TTabSheet *TS;
TPSX_FRM *FRM;// = (TPSX_FRM *)MyFrame->Parent;

TS = (TTabSheet *)MyFrame->Parent;
FRM = (TPSX_FRM *)TS->PageControl->Parent;

// create the message queue
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);

// wait for messages
while( (GetMessage(&msg, NULL, 0, 0) > 0) && (!Terminated) )
{
// based on the message do something
switch( msg.message )
{
case THREADMSG_START_SCAN:
Position = 0;
FRM->Progress = 0;
FRM->PSX_SB->Invalidate();
// clear settings for scan
memset(Sector, 0, 409600);
Scaning = true;
ScanImage();
break;
case THREADMSG_STOP_SCAN:
Scaning = false;
break;
case THREADMSG_CONT_SCAN:
Scaning = true;
ScanImage();
break;
}
}
}

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

#define BFR_SIZE 0x040000
#define F_HEADER 0x008000

void TScan::ScanImage()
{
fstream File;
TPSX_FRM *FRM;
TTabSheet *TS;
int EndOfBuffer,
EndOffile;
bool DontRead;
UINT8 *ScanBuf;

TS = (TTabSheet *)MyFrame->Parent;
//=
FRM = (TPSX_FRM *)TS->PageControl->Parent;
File.open(Path.c_str(), fstream::binary | fstream::in);
// if the file is open
if(File.is_open())
{
// go to Position
File.seekg(Position);
// while we are still scanning
DontRead = false;
while(Scaning)
{
if(!Terminated)
{
// do we need to read data into the buffer?
if(!DontRead)
{ // we need to add data to our buffer

}
else
{
// we have data in the buffer so
// we look for what we are looking for here
ScanBuf = &Sector[Position & (BFR_SIZE - 1)];
if(is_tim(ScanBuf))
{
// set up information in the data tree regarding
// this
}
else
{
}
}
// update main form information
Scaning = (Position < FRM->MaxProg);
FRM->Progress = Position;
FRM->PSX_SB->Invalidate();
}
else
Scaning = false;
}
}
Scaning = false;
}
//-------------------------------------------------------------------------
--
void __fastcall TScan::StartScan(void)
{
Terminated;
PostThreadMessage(ThreadID, THREADMSG_START_SCAN, 0, 0);
}
//-------------------------------------------------------------------------
--
void __fastcall TScan::StopScan(void)
{
Terminated;
PostThreadMessage(ThreadID, THREADMSG_STOP_SCAN, 0, 0);
Scaning = false;
}
//-------------------------------------------------------------------------
--
void __fastcall TScan::ContinueScan(void)
{
PostThreadMessage(ThreadID, THREADMSG_CONT_SCAN, 0, 0);
}
//-------------------------------------------------------------------------
--
void __fastcall TScan::TerminateThread(TObject *Sender)
{
// kill our thread
Terminate();
PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
delete Sector;
}
//-------------------------------------------------------------------------
--
// Check Scan for a valid TIM file type
//-------------------------------------------------------------------------
--
bool is_tim(UINT8 *Scan)
{
base_tim_hdr *TH;
bool Return;

// check for TIM magic # in first little endian DWORD
TH = (base_tim_hdr *)Scan;
Return = (TH->Magic == TIM_MAGIC);
// if begins with TIM_MAGIC ID
if(Return)
{
// we should check to see what type
switch(TH->Type)
{
case TIM_4BPP:
Return = is_tim_04(Scan);
break;
case TIM_8BPP:
Return = is_tim_08(Scan);
break;
case TIM_16BPP:
Return = is_tim_16(Scan);
break;
case TIM_24BPP:
Return = is_tim_24(Scan);
break;
default:
// we should never see this value in a valid TIM
Return = false;
break;
}
}
return Return;
}
//-------------------------------------------------------------------------
--
bool is_tim_04(UINT8 *Scan)
{
tim_4bpp *Base;
bool Return;

Base = (tim_4bpp *)Scan;
// do we have a rediculous number of palettes?
Return = (Base->CLUT_CNT <= 32);
if(Return)
{
// possibly a TIM still
// do we have a rediculous size?
Return = (Base->Bytes <= (2 << 19));
if(Return)
{
// we are not oversized
// is the X palette location SANE?
Return = (Base->PALX < 1024);
if(Return)
{
// is the Y Palette location sane?
Return = (Base->PALY < 511);
if(Return)
{
base_tim_img *TimImage;

TimImage = (base_tim_img *)(
Scan + sizeof(tim_4bpp) + sizeof(CLUT_4bpp)*Base-
Quote:
CLUT_CNT);
// does it start in a sane location?

Return =((TimImage->IMGX < 1023)&&
(TimImage->IMGY < 511));
if(Return)
{
// is it a sane size?
Return =
(((TimImage->Pitch * 4) <= 1024)&&
(TimImage->Height < 512));
if(Return)
{
// if number of words is incorrect
Return = (TimImage->WCount != (TimImage->Pitch * TimImage-
Quote:
Height));
}

}
}
}
}
}
return Return;
}
//-------------------------------------------------------------------------
--
bool is_tim_08(UINT8 *Scan)
{
tim_8bpp *Base;
bool Return;

Base = (tim_8bpp *)Scan;
// do we have a Sane number of palettes?
Return = (Base->CLUT_CNT <= 16);
if(Return)
{
// possibly a TIM still
// do we have a rediculous size?
Return = (Base->Bytes <= (2 << 19));
if(Return)
{
// we are not oversized
// is the X palette location SANE?
Return = (Base->PALX < 1024);
if(Return)
{
// is the Y Palette location sane?
Return = (Base->PALY < 511);
if(Return)
{
base_tim_img *TimImage;

TimImage = (base_tim_img *)(
Scan + sizeof(tim_8bpp) + sizeof(CLUT_8bpp)*Base-
Quote:
CLUT_CNT);
}

}
}
}
return Return;
}
//-------------------------------------------------------------------------
--
bool is_tim_16(UINT8 *Scan)
{
tim_16bpp *Base;

//Base = (tim_16bpp *)Scan;

return false;
}
//-------------------------------------------------------------------------
--
bool is_tim_24(UINT8 *Scan)
{
tim_24bpp *Base;

//Base = (tim_24bpp *)Scan;

return false;
}
//-------------------------------------------------------------------------
--
---------------------------------------------------------------------------

Thanks for any feed back of what I might be doing wrong here (sigh).

Stephen

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Mon Jul 25, 2005 5:59 pm    Post subject: Re: Frames and terminating the threads that belong to them ( Reply with quote


"Stephen R. Phillips" <cyberman_phillips (AT) yahoo (DOT) com> wrote


Quote:
I cannot get my thread to execute.

That is because you are not using it correctly.

Quote:
TScan(bool);// : TThread(false);

You need to use the __fastcall calling convention when declaring VCL
constructors (and destructors):

__fastcall TScan(bool);// : TThread(false);
// __fastcall ~TScan();

Quote:
void __fastcall TerminateThread(TObject *);

class TSCAN_FILE : public TFrame

You should not be using all caps for your own types. That is reserved
behavior for the C++ language. Give your class a more meaningful name, ie:

class TScanFile : public TFrame

Quote:
Scanner = new TScan(false);
Scanner->Position = 0;
Scanner->MyFrame = this;

You are setting the CreateSuspended parameter to false, which means the
thread will begin running right away even before the thread's constructor
has finished. However, you are doing additional initializations both
inside the constructor and outside of it, that the thread depends on in
order to function properly. You should always set CreateSuspended to true
whenever you need to initialize anything that the thread will access, and
then call Resume() after all initializations have been finished. Otherwise,
you risk crashing your thread, if not the entire program altogether.

Quote:
for(Index = this->ControlCount -1; Index > -1; Index--)
{
// get the control
Ctrl = this->Controls[Index];
// remove the control
this->RemoveControl(Ctrl);
//delete the control
delete Ctrl;
}

You don't need to do any of that. The VCL already does all of that for you
automatically. When a component has an Owner assigned, the Owner
automatically frees the component when the Owner itself is freed.

Quote:
// remove the scaner object
Scanner->TerminateThread(Scanner);
delete Scanner;

Your TerminateThread() method is requesting the thread to terminate itself,
but it is not actually waiting for the thread to fully terminate before you
then 'delete' the thread object. You should be calling the thread's
WaitFor() method before calling 'delete'.

Quote:
TScan::TScan(bool CreateSuspended) : TThread(CreateSuspended)
{
Sector = new UINT8[409600];
Terminated;
setmem(Sector, 0, 409600);
//this->OnTerminate = TerminateThread;
}

Why are you accessing the Terminated property in the constructor? That is
not doing anything for you at all.

Also, like I said above, you are initializing the thread after it is already
running. Also, you are doing some initializations after the thread
constructor has finished. You should be doing ALL initializations inside
the constructor only. That is what a constructor is for:

class TScan : public TThread
{
//...
protected:
void __fastcall AfterConstruction();
//...
public:
__fastcall TScan(TFrame *AFrame);
//...
};

__fastcall TScan::TScan(TFrame *AFrame)
: TThread(true)
{
Sector = new UINT8[409600];
setmem(Sector, 0, 409600);
Position = 0;
MyFrame = AFrame;
}

void __fastcall TScan::AfterConstruction()
{
Resume();
}

__fastcall TSCAN_FILE::TSCAN_FILE(TComponent* Owner)
: TFrame(Owner)
{
//...
Scanner = new TScan(this);
//...
}

Quote:
bool __fastcall TScan::Busy(void)
{
Terminated;
return Scaning;
}

Again, why are you accessing the Terminated property? You are not using its
value for anything meaningful, so accessing it is useless.

Quote:
TPSX_FRM *FRM;// = (TPSX_FRM *)MyFrame->Parent;
TS = (TTabSheet *)MyFrame->Parent;

That will crash in your current code, since MyFrame has not been set yet
when Execute() begins runs. The changes I mentioned above will fix that.

Quote:
FRM->Progress = 0;
FRM->PSX_SB->Invalidate();

You need to use the thread's Synchronize() method whenever you acess the
GUI. For the most part, the VCL, especially the GUI aspects of it, are NOT
thread-safe at all.

Quote:
// clear settings for scan
memset(Sector, 0, 409600);

You are not setting all of the bytes that you allocated. That call should
be this instead:

memset(Sector, 0, sizeof(UINT8) * 409600);

Quote:
Scaning = (Position < FRM->MaxProg);
FRM->Progress = Position;
FRM->PSX_SB->Invalidate();

Again, you must use Synchronize() for that.

Quote:
void __fastcall TScan::StartScan(void)
{
Terminated;
PostThreadMessage(ThreadID, THREADMSG_START_SCAN, 0, 0);
}

Again, why are you accessing the Terminated property?

Quote:
void __fastcall TScan::StopScan(void)
{
Terminated;
PostThreadMessage(ThreadID, THREADMSG_STOP_SCAN, 0, 0);
Scaning = false;
}

Again, why are you accessing the Terminated property?

Quote:
void __fastcall TScan::TerminateThread(TObject *Sender)
{
// kill our thread
Terminate();
PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
delete Sector;
}

Like I mentioned earlier, you should be calling the thread's WaitFor()
method after requesting the thread to terminate itself.

Also, you should move the 'delete' into the thread's destructor, especially
since you allocated the memory in the constructor.


Gambit



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Development) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.