Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Threaded Functions

0.00/5 (No votes)
5 Nov 2011BSD 6K  
Here's an interesting thought experiment for functions that get executed in a separate thread.

Here's an interesting thought experiment for functions that get executed in a separate thread.

C++
void doit( int i ) {
   printf( "Hello from doit! i: %d\n", i );
}

void doit2( Thread* th, int i ) {
  printf( "Hello from doit2! i: %d, th: %p, tid: 0x%04x \n", 
          i, th, th->getThreadID() );
}

class Snarfy {
public:
  void thisBlows( int g ) {
     printf( "Hello from thisBlows! i: %d, this ptr: %p\n", g, this );
  }
};

class Swanky {
public:
  void doit( double& d, const String& s ) {
     printf( "Hello from Swanky::doit! d: %0.3f, s: %s, this ptr: %p\n",
               d, s.ansi_c_str(), this );
  }

  void doit2( Thread* th, double& d, const String& s ) {
     printf( "Hello from Swanky::doit! d: %0.3f, s: %s, this ptr: %p\n",
               d, s.ansi_c_str(), this );

     for (int i=0;i<10;i++){
       th->sleep(1000);
   }
}
};

int main( int argc, char** argv ){
FoundationKit::init( argc, argv );

Thread* th = ThreadedProcedure1<int>(10,doit);
th->wait();
th = ThreadedProcedure1<int>(231,doit2);
th->wait();

Snarfy sn;
th = ThreadedProcedure1<int,Snarfy >(&sn,38112,&Snarfy::thisBlows);
th->wait();

String s = "hello";
Swanky sk;

double d = 0.0332;

th = ThreadedProcedure2< double&,const String&, 
      Swanky >(&sk,d,s,&Swanky::doit2);
th->wait();

printf( "Bye!\n");

FoundationKit::terminate();
return 0;

The actual implementation gets a bit long winded, but looks something like this:

C++
template <typename ParamType1>
class NullClassType1 {
 public:
  void m(ParamType1){}
  void m(Thread*, ParamType1){}
};

template <typename ParamType1, typename ClassType=NullClassType1<ParamType1> >
class ThreadedProcedure1: public Runnable {
public:

 typedef NullClassType1<ParamType1> NullClassType;

 typedef void (*ProcPtr1)(ParamType1 p1);
 typedef void (*ProcThreadPtr1)(Thread* thread, ParamType1 p1); 

 typedef void (ClassType::*ClassProcPtr1)( ParamType1 p1 );
 typedef void (ClassType::*ClassThreadProcPtr1)( Thread* thread, ParamType1 p1 );

 

 ThreadedProcedure1( ParamType1 p1, ProcPtr1 procPtr ): param1_(p1),
  runningThread_(NULL),
   procPtr_(NULL),
   procThreadPtr_(NULL),
   classProcPtr_(NULL),
   classThreadProcPtr_(NULL),
   instancePtr_(NULL){

  ThreadedProcedure1<ParamType1,ClassType>* params = 
   new ThreadedProcedure1<ParamType1,ClassType>(p1);

  params->procPtr_ = procPtr;

  runningThread_ = new Thread( params, true, true );
  params->runningThread_ = runningThread_;

  runningThread_->start();
 }

 ThreadedProcedure1( ParamType1 p1, ProcThreadPtr1 procPtr ): param1_(p1),
   runningThread_(NULL),
   procPtr_(NULL),
   procThreadPtr_(NULL),
   classProcPtr_(NULL),
   classThreadProcPtr_(NULL),
   instancePtr_(NULL){

  ThreadedProcedure1<ParamType1,ClassType>* params = 
   new ThreadedProcedure1<ParamType1,ClassType>(p1);

  params->procThreadPtr_ = procPtr;

  runningThread_ = new Thread( params, true, true );
  params->runningThread_ = runningThread_;

  runningThread_->start();
 }

 ThreadedProcedure1( ClassType* src, ParamType1 p1, ClassProcPtr1 procPtr ): param1_(p1),
  runningThread_(NULL),
   procPtr_(NULL),
   procThreadPtr_(NULL),
   classProcPtr_(NULL),
   classThreadProcPtr_(NULL),
   instancePtr_(NULL) {

  ThreadedProcedure1<ParamType1,ClassType>* params = 
   new ThreadedProcedure1<ParamType1,ClassType>(p1);


  params->classProcPtr_ = procPtr;
  params->instancePtr_ = src;

  runningThread_ = new Thread( params, true, true );
  params->runningThread_ = runningThread_;

  runningThread_->start();
 }


 ThreadedProcedure1( ClassType* src, ParamType1 p1, 
                     ClassThreadProcPtr1 procPtr ): param1_(p1),
   runningThread_(NULL),
   procPtr_(NULL),
   procThreadPtr_(NULL),
   classProcPtr_(NULL),
   classThreadProcPtr_(NULL),
   instancePtr_(NULL){

  ThreadedProcedure1<ParamType1,ClassType>* params = 
   new ThreadedProcedure1<ParamType1,ClassType>(p1);

  params->classThreadProcPtr_ = procPtr;
  params->instancePtr_ = src;

  runningThread_ = new Thread( params, true, true );
  params->runningThread_ = runningThread_;

  runningThread_->start();
 }


protected:

 ThreadedProcedure1( ParamType1 p1 ): param1_(p1),
   runningThread_(NULL),
   procPtr_(NULL),
   procThreadPtr_(NULL),
   classProcPtr_(NULL),
   classThreadProcPtr_(NULL),
   instancePtr_(NULL){
 }

public:
 virtual bool run() {


  if ( typeid(ClassType) == typeid(NullClassType) ) {
   if ( NULL != procThreadPtr_ ) {
    (*procThreadPtr_)( runningThread_, param1_ );
   }
   else if ( NULL != procPtr_ ) {
    (*procPtr_)( param1_ );
   }
   else {
    return false;
   }   
  }
  else {
   if ( NULL != instancePtr_ ) {
    if ( NULL != classThreadProcPtr_ ) {
     (instancePtr_->*classThreadProcPtr_)( runningThread_, param1_ );
    }
    else if ( NULL != classProcPtr_ ) {
     (instancePtr_->*classProcPtr_)( param1_ );
    }
    else {
     return false;
    } 
    
   }
  }
  

  return true;
 }

 virtual void stop(){}


 operator Thread* () {
  return runningThread_;
 }
protected:
 
 ParamType1 param1_;
 Thread* runningThread_;
 ProcPtr1 procPtr_;
 ProcThreadPtr1 procThreadPtr_;
 ClassProcPtr1 classProcPtr_;
 ClassThreadProcPtr1 classThreadProcPtr_;
 ClassType* instancePtr_;
};

This allows us to attach a function and execute it in a separate thread, using the various VCF thread classes, such as VCF::Thread and VCF::Runnable to implement it. I'll leave it as an exercise for the reader to add additional arguments. If people like this enough we'll probably put this into the FoundationKit proper.

License

This article, along with any associated source code and files, is licensed under The BSD License