Click here to Skip to main content
15,881,424 members
Articles / Desktop Programming / Win32
Article

A homebrewed lightweight scheduler

Rate me:
Please Sign up or sign in to vote.
2.44/5 (9 votes)
13 Feb 2008CPOL1 min read 31.4K   18   3
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.

C++
//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

C++
/*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.

C++
#include <windows.h>
#include "stdafx.h"
#include "Scheduler.h"

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

C++
#include "Scheduler.h"
#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_);
}

C++
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)


Written By
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? Pin
d3nika20-Aug-10 20:37
d3nika20-Aug-10 20:37 
GeneralGood job Pin
Sudhir Mangla13-Feb-08 21:28
professionalSudhir Mangla13-Feb-08 21:28 
GeneralRe: Good job Pin
pradeep shivadasan14-Feb-08 17:19
pradeep shivadasan14-Feb-08 17:19 

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

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