[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3127
  • Last Modified:

threads in C++ builder 3

I want to execute  MyPrint(){some very basic but large data} when I press abutton, and I want to do it with a thread so I do have to wait to the printer to finish their work.
I want to use the File|new...|thread Object of IDE. I got

__fastcall ThPrint::ThPrint(bool CreateSuspended)
 : TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall ThPrint::Execute()
{
    //---- Place thread code here ----
   Form1->Synchronize(MyPrint()); ?
}
 where do I start the thread?
 do I need to use new?
 where do I place the Resume?
 Do I have to use TThreadMethod?

Thank you very much for your help, any comments are welcomed.
0
FMJMEE
Asked:
FMJMEE
  • 4
  • 3
  • 3
1 Solution
 
AlexVirochovskyCommented:
   TThread cannot be used as-is.  You must derive a class from TThread
    as demonstrated in example TThreads. Next is snippet of code
(file sortthd.h poject TThreads):
//----------------------------------------------------------------------------
//Borland C++Builder
//Copyright (c) 1987, 1997 Borland International Inc. All Rights Reserved.
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef SortThdH
#define SortThdH
//----------------------------------------------------------------------------
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
#include <Classes.hpp>
#include <System.hpp>
//----------------------------------------------------------------------------
extern void __fastcall PaintLine(TCanvas *Canvas, int i, int len);
//----------------------------------------------------------------------------
class TSortThread : public TThread
{
private:
      TPaintBox *FBox;
      int *FSortArray;
      int FSize;
      int FA;
      int FB;
      int FI;
      int FJ;
      void __fastcall DoVisualSwap(void);

protected:
      virtual void __fastcall Execute(void);
      void __fastcall VisualSwap(int A, int B, int I, int J);
      virtual void __fastcall Sort(int *A, const int A_Size) = 0;
      
public:
      __fastcall TSortThread(TPaintBox *Box, int *SortArray,
          const int SortArray_Size);
};
//----------------------------------------------------------------------------
class TBubbleSort : public TSortThread
{
protected:
      virtual void __fastcall Sort(int *A, const int A_Size);
public:
      __fastcall TBubbleSort(TPaintBox *Box, int *SortArray,
          const int SortArray_Size);
};
//----------------------------------------------------------------------------
class TSelectionSort : public TSortThread
{
protected:
      virtual void __fastcall Sort(int *A, const int A_Size);
public:
      __fastcall TSelectionSort(TPaintBox *Box, int *SortArray,
          const int SortArray_Size);
};
//----------------------------------------------------------------------------
class TQuickSort : public TSortThread
{
protected:
      void __fastcall QuickSort(int *A, const int A_Size, int iLo,
        int iHi);
      virtual void __fastcall Sort(int *A, const int A_Size);
public:
      __fastcall TQuickSort(TPaintBox *Box, int *SortArray,
          const int SortArray_Size);
};
//----------------------------------------------------------------------------
#endif
If you want full code of Project in BCB4, write you EMail
Alex 
0
 
FMJMEEAuthor Commented:
How can I do some printing in a thread?
I already have that example.
Correction!. My question say "..so I do have to wait for the printer... ", must say "so I do NOT have to wait for the printer " I will appreciate any comments
 Thank you very much for your help!
0
 
AlexVirochovskyCommented:
Next is answer, how to use TThread class in BCB3(not 4!)
You must use this code and inplement you function Run(),
as can be Print.

Question and Answer Database

FAQ2373C.txt   TThread Run () in OWL
Category   :OWL
Platform    :All
Product    :C++Builder  3.x

Question:
How to use Run () in a TThread in OWL?

Answer:
There is a missing function in the docs:

virtual int Run();

Basically, it goes like this:

a) You derive from TThread and override Run().  Any code executing from this
Run() is in the new thread owned by the TThread class.

b) When you call Start() will your new thread object, TThread creates a new
windows thread and makes it call your Run() function

c) You have to be aware of the valid states and state transitions.  For
example, when you create a new TThread object, it is in the TThread::Created
state.  The only valid transition is to TThread::Running (this is done by
calling Start()).  So in other words, you can't create a TThread object and
not call its Start(). If you try to delete this object before calling
Start(), it will throw an exception.  Also, the new thread is done when you
return from Run() or when you call Exit() (i think).  Basically, you must
call Start() exactly once for each instance of TThread.  This means that you
must call Start() before deleting the object and you can only can Start()
once during the lifetime of the object.  All this kind of stuff is in the
docs, but I thought I would mention it anyway.

If you want a slick way of controlling a thread without being required to
derive from it, check out the code below.

Basically, any class that needs multithreading, just derive from Runnable
and override int Run().  When you're ready, you can create a new ThreadEx
object like:


// assuming 'this' is an instance of an object derived
// from Runnable
//
ThreadEx* mythread = new ThreadEx(this);
myThread->Start();

you now have an object that can USE threads without being a thread object
itself and without having to create a separate DoSomethingInAnotherThread
class derived from TThread every time you need another functionality in
separate thread.  The object using a ThreadEx can create a new thread, run
it, delete it, create another, run it, delete it ....

Here is the code:


//
// declaration
//
class ThreadEx;

class Runnable {
  public:
    Runnable();

  protected:
    virtual int Run() = 0;

    friend ThreadEx;
};

class ThreadEx : public TThread {
  public:
    ThreadEx(Runnable* runnable);
    virtual ~ThreadEx();

    int Run();
    bool ShouldTerminate();
    TThread::THandle Start();
    TThread::THandle GetHandle();
    void Kill();


  protected:
    Runnable* runnable;
    TThread::THandle threadHandle;
};



//
//
// Runnable implementation
//
Runnable::Runnable() {
}

//
//
// ThreadEx implementation
//
ThreadEx::ThreadEx(Runnable* runnable) {
  if(runnable == NULL)
    xmsg("ThreadEx: Invalid Runnable").raise();

  this->runnable = runnable;
}

ThreadEx::~ThreadEx() {
  switch(GetStatus()) {
    case Created:  Start();
    case Suspended:  Resume();
    case Running:  TerminateAndWait(5000);
          if(GetStatus() != Finished)
                       Kill();
                     break;
  }
}

TThread::THandle ThreadEx::Start() {
  threadHandle = TThread::Start();
  return threadHandle;
}

TThread::THandle ThreadEx::GetHandle() {
  return threadHandle;
}

//
// Avoid using Kill().  It will obliterate the thread and any resources that
were allocated by
// your code will not be freed.
//
void ThreadEx::Kill() {
  ::TerminateThread(threadHandle, 0);
}

bool ThreadEx::ShouldTerminate() {
  return TThread::ShouldTerminate();
}

int ThreadEx::Run() {
  return runnable->Run();
}

I hope, it helps. Alex
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
FMJMEEAuthor Commented:
Sorry! I can´t get the point, the code is confusing, and I don´t see anything better than what I already have.
Thanks.
0
 
AlexVirochovskyCommented:
This article is the reply of Borland
Team. Thus all reproachs are to
Borland! For me text is clear, but
I have BCB4 and can't test it.
Sorry, but i can't more help you.
Alex
0
 
alcindorCommented:
Using your original example code, I can uillustrate the answers to your questions. I will answer the questions first and add some code to your example below.

You must first create an instance of your thread class ( yes you do need to use new ) and specify createsuspended as true, this creates your thread object but no execution of the thread begins yet ( except for code in the thread construcor )

Using the pointer to your thread object you can start the thread from a buttonclick event handler by calling the Resume() method of the threaad object. This statrts the threads Execute() function which is typically an endless loop which is terminated by calling the thread objects Terminate() method ( or additionally in your case, when the printing has finished ? )


__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
  // create thread object suspended
  yourthread = new ThPrint(true);

}

__fastcall TForm1::~TForm1()
{
  yourthread->Terminate();
}


void __fastcall TForm1::Button1Click(TObject *Sender)
{// start the thread in not already started

  if(yourthread->Suspended)
     yourthread->Resume();
}
 
bool TForm1::MyPrint()
{// pseudo - code
   if(printingnotstatrted)
   {
     startprinting process..
     return false;
   }
   else
   if(printingfinished)
       return true;
   else
       return false;

}

__fastcall ThPrint::ThPrint(bool CreateSuspended)
    : TThread(CreateSuspended)
{
    // simplify cleanup when finished
    FreeOnTerminate = true;
}
//---------------------------------------------------------------------------
void __fastcall ThPrint::Execute()
{
    for(finished = false;Terminated==false&&!finished;)
    {
        Synchronize(DoPrinting);
        Sleep(500); // give some time up for more useful tasks ?
    }
}

void __fastcall ThPrint::DoPrinting()
{   // initial call to MyPrint() starts printing,
    // MyPrint() should return true only when printing has finished
  finished = Form1->MyPrint();
}
0
 
FMJMEEAuthor Commented:
Well done, how about passing a parameter (integer) to:  TForm1::MyPrint(), is it possible?

Thank you very much
0
 
alcindorCommented:
Thanks for the points. In answer to your question regarding passing a parameter, Yes, it is possible to pass an integer parameter; just declare it in the member function prototype as normal.

bool TForm1::MyPrint(int param)
{// pseudo - code
   if(printingnotstatrted)
   {
     startprinting process..
     using param as needed ..
     return false;
   }
   else
   if(printingfinished)
       return true;
   else
       return false;
}

0
 
FMJMEEAuthor Commented:
I mean at Synchronize(DoPrinting);
because I get an error message here if I use : Synchronize(DoPrinting(4));
any hint?

Thanks for your time, best regards
               
0
 
alcindorCommented:
Unfortunately, you can't pass a parameter in the Synchronize() function. You may however, declare and use a variable in your ThPrint class and have your DoPrinting() function use it. You could set the variable either in your Execute() function, in your ThPrint constructor or even by adding a public memeber funtion to ThPrint such as
void ThPrint::SetParameter(int p){param = p};

Good luck & merry Xmas.
0

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 4
  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now