Click here to Skip to main content
Click here to Skip to main content

A homebrewed lightweight scheduler

, 13 Feb 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
timer based task scheduler

Introduction

There are times when a task has to be executed at a predetermined time interval. The solution presented here is a set of C++ classes that provides a wrapper around the TimerQueue API.

Using the code

The scheduler consists of CTask class and a CScheduler class... The scheduler maintains a list of tasks which will be executed by the scheduler once the timer associated with the task expires. When the task is executed by the scheduler, the user defined callback function which is cached inside the CTask class gets executed. The scheduler provides interface to queue new tasks and cancel tasks enqued by the user.

Following is the class declaration for CTask class.

           
//Unit of execution scheduled by CScheduler 
class CTask{

friend VOID CALLBACK CTimerScheduler::WaitOrTimerCallback(PVOID lpParameter,BOOLEAN TimerOrWaitFired);

private:
HANDLE hQueueTimer_; //handle to timerqueue for this task
void(*callback_)(void);//user defined callback function
CScheduler& sched_;//the scheduler

public: 
CTask(CScheduler& sched, void(*callback)(void)) :
hQueueTimer_(0), sched_(sched), callback_(callback){}
void setHandle(HANDLE hQueueTimer);
void finish();
};


Following is the class declaration for CScheduler

     
/*Prototypes of functions to be pulled from kernel32.dll*/

typedef VOID (CALLBACK *WAITORTIMERCALLBACK)(PVOID lpParameter,BOOLEAN TimerOrWaitFired); 

typedef HANDLE (*CREATETIMERQUEUE)(void);

typedef BOOL (CALLBACK *CREATETIMERQUEUETIMER)(
PHANDLE phNewTimer,
HANDLE TimerQueue, 
WAITORTIMERCALLBACK callback,
PVOID Parameter,
DWORD DueTime,
DWORD Period,
ULONG Flags
);

typedef BOOL (CALLBACK *DELETETIMERQUEUETIMER)(
HANDLE TimerQueue,
HANDLE Timer,
HANDLE CompletionEvent
);

typedef BOOL (CALLBACK *DELETETIMERQUEUE)(
HANDLE TimerQueue
);

/**/

class CScheduler{ 
friend CTask;

friend VOID CALLBACK WaitOrTimerCallback(PVOID lpParameter,BOOLEAN TimerOrWaitFired);

private:
unsigned long interval_;
list<CTask*> tasks_;
HANDLE hTimer_; 
HMODULE hLibrary_;
static CRITICAL_SECTION cs_;

private:
static VOID CALLBACK WaitOrTimerCallback(PVOID lpParameter,BOOLEAN TimerOrWaitFired);

CREATETIMERQUEUE createTimer;

DELETETIMERQUEUE deleteTimerQueue;

CREATETIMERQUEUETIMER createTimerQueueTimer;

DELETETIMERQUEUETIMER deleteTimerQueueTimer;

public: 
~CScheduler();
void start();
void stop();
void enqueueTask(int interval, void (*callback)(void));
void removeTask(CTask* task);
void cancelTasks();
};

To use these classes in your code copy the code into respective files and include the same in your project.

#include <span class="code-keyword"><windows.h></span>
#include <span class="code-string">"stdafx.h"</span>
#include <span class="code-string">"Scheduler.h"</span>

void UserSuppliedFunction(){
 static int x = 0; 
 printf("function called %ld\n", ++x);
}
int main(int argc, char* argv[])
{
 CScheduler sched;
 sched.start();
 unsigned int i = 0xFFFFFFFF;
 while( i-- ){
  sched.enqueueTask((i/10000000)*2, UserSuppliedFunction);  
  Sleep(5);
  if( (i%100) == 0 ){
   printf("cancelling....\n");
   sched.cancelTasks();
  }
 }
 sched.cancelTasks();
 sched.stop();
 Sleep(1000);
 return 0;
}
  

Following is the implementation of the classes

#include <span class="code-string">"Scheduler.h"</span>
#include <assert.h />

CRITICAL_SECTION CScheduler::cs_ ;


void
CScheduler::start(){
    hLibrary_   = LoadLibrary("kernel32");
    createTimer = 
          (CREATETIMERQUEUE)GetProcAddress(hLibrary_, "CreateTimerQueue");
    deleteTimerQueue = 
          (DELETETIMERQUEUE)GetProcAddress(hLibrary_, "DeleteTimerQueue");
    createTimerQueueTimer = 
     (CREATETIMERQUEUETIMER)GetProcAddress(hLibrary_, "CreateTimerQueueTimer");
    deleteTimerQueueTimer = 
     (DELETETIMERQUEUETIMER)GetProcAddress(hLibrary_, "DeleteTimerQueueTimer");

    InitializeCriticalSection(&cs_);
    hTimer_ = createTimer();
}

void
CScheduler::stop(){
    cancelTasks();
    deleteTimerQueue(hTimer_);    
    DeleteCriticalSection(&cs_);
    FreeLibrary(hLibrary_);
}

void
CScheduler::enqueueTask( int interval, void(*callback)(void) ){

    CTask* newTask = new CTask(*this, callback);    
    HANDLE hQueueTimer = 0;

        EnterCriticalSection(&cs_);
    createTimerQueueTimer(                        &hQueueTimer, hTimer_,                        (WAITORTIMERCALLBACK)WaitOrTimerCallback,                        (void*)newTask,                        interval, 0, WT_EXECUTEINPERSISTENTTHREAD | WT_EXECUTEONLYONCE );
    newTask->setHandle(hQueueTimer);
    tasks_.push_back(newTask);

       LeaveCriticalSection(&cs_);
}

void
CScheduler::cancelTasks(){

    EnterCriticalSection(&cs_);
    while(1){
        list<ctask* />::iterator iter = tasks_.begin();
        if(iter == tasks_.end()) break;
        iter.operator *()->finish();
    }
    LeaveCriticalSection(&cs_);
}

void
CScheduler::removeTask(CTask* task){    
    tasks_.remove(task);    
    delete task;    
}

VOID CALLBACK 
CScheduler::WaitOrTimerCallback(PVOID lpParameter,BOOLEAN TimerOrWaitFired){

    EnterCriticalSection(&CScheduler::cs_);
    CTask* task = static_cast<ctask* />(lpParameter);
    task->callback_();
    task->finish();
    LeaveCriticalSection(&CScheduler::cs_);
}

  

void
CTask::setHandle(HANDLE hQueueTimer){
    hQueueTimer_ = hQueueTimer;
}

void
CTask::finish(){
    sched_.deleteTimerQueueTimer(sched_.hTimer_, hQueueTimer_, NULL);
    sched_.removeTask(this);
}

This is the first release of the software and following updation can be expected in the further versions... Presently the task can be executed only once which can be made to executed periodically... User defined function arguments can be cached in CTask class and can be passed as parameter to the callback function.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

pradeep shivadasan
Software Developer (Senior) VisioSpect Systems Pvt. Ltd.
India India
Pradeep lives in ahmedabad and earns his living by programming computers...
he is passionate about devices that can be programmed and can programm anything from a pc to embedded chips...
 
when he is not writing codes he loves sleeping Smile | :)

Comments and Discussions

 
QuestionIs it working within a service app? Pinmemberd3nika20-Aug-10 21:37 
GeneralGood job PinmemberSudhir Mangla13-Feb-08 22:28 
GeneralRe: Good job Pinmemberpradeep shivadasan14-Feb-08 18:19 
Thanx buddy... if you know any further assistance or the source code do let me know.
 
Real programmers don't comment their code. If it was hard to write it should be hard to understand.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 14 Feb 2008
Article Copyright 2008 by pradeep shivadasan
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid