blob: ca7725547af8163d8bf0f69b780b002e252c62f5 [file] [log] [blame]
//
// Thread.h: header file
//
// Copyright (C) Walter E. Capers. All rights reserved
//
// This source is free to use as you like. If you make
// any changes please keep me in the loop. Email them to
// walt.capers@comcast.net.
//
// PURPOSE:
//
// To implement Win32 threading as a C++ object
//
// REVISIONS
// =======================================================
// Date: 10.24.07
// Name: Walter E. Capers
// Description: File creation
//
// Date: 10.24.07 11:49 am
// Name: Walter E. Capers
// Description: Added SetIdle function to allow the idle time to be altered
// independent of the SetThreadType member function.
// Date: 10.31.07
// Name: Walter E. Capers
// Description: Added support for beginthreadex
// To use compile with -DUSE_BEGIN_THREAD
//
//
#ifndef THREAD_CLASS
#define THREAD_CLASS
#ifndef WINDOWS
#if defined(_WIN32) || defined(_WIN64)
#define WINDOWS
#endif
#endif
#ifdef __APPLE__
#define VMS
#endif
#ifndef WINDOWS
#include <stdio.h>
#include <string.h>
//#include <malloc.h>
#include <memory.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
typedef long DWORD;
typedef void *LPVOID;
#else
#include "afx.h"
/* #include <windows.h> */
#include <stdio.h>
#endif
#if defined(AS400) || defined(OS400)
typedef pthread_id_np_t ThreadId_t;
#elif defined(VMS) || defined(__NetBSD__)
typedef pthread_t ThreadId_t;
#else
#ifdef USE_BEGIN_THREAD
typedef unsigned ThreadId_t;
#else
typedef DWORD ThreadId_t;
#endif
#endif
#include <common/MutexClass.h>
#include <common/EventClass.h>
#define QUEUE_SIZE 100
#define DEFAULT_STACK_SIZE 0
#ifndef WINDOWS
void Sleep( unsigned int mseconds);
#endif
#ifndef ASSERT
#if defined(DEBUG) || defined(_DEBUG)
#define ASSERT(test) if( !(test) ) { \
fprintf(stderr,"\nASSERT(%s) FAILS, %s line %d\n",#test,__FILE__, __LINE__); exit(0);}
#else
#define ASSERT(test)
#endif
#endif
typedef enum {
ThreadStateBusy, // thread is currently handling a task
ThreadStateWaiting, // thread is waiting for something to do
ThreadStateDown, // thread is not running
ThreadStateShuttingDown, // thread is in the process of shutting down
ThreadStateFault // an error has occured and the thread could not
// be launched
} ThreadState_t;
typedef enum {
ThreadTypeHomogeneous,
ThreadTypeSpecialized,
ThreadTypeIntervalDriven,
ThreadTypeNotDefined } ThreadType_t;
typedef enum {
TaskStatusNotSubmitted,
TaskStatusWaitingOnQueue,
TaskStatusBeingProcessed,
TaskStatusCompleted } TaskStatus_t;
class CTask
{
private:
TaskStatus_t m_state;
ThreadId_t m_dwThread;
public:
CMutexClass m_mutex;
void SetTaskStatus(TaskStatus_t state)
{
m_mutex.Lock();
m_state=state;
m_mutex.Unlock();
}
void SetId(ThreadId_t *pid)
{
memcpy(&m_dwThread,pid,sizeof(ThreadId_t));
}
/**
*
* Wait
* waits for upto timeoutSeconds for a task
* to complete
*
**/
BOOL Wait(int timeoutSeconds)
{
timeoutSeconds = timeoutSeconds * 1000;
if( Status() != TaskStatusCompleted &&
timeoutSeconds > 0 )
{
Sleep(100);
timeoutSeconds = timeoutSeconds - 100;
}
if( Status() == TaskStatusCompleted ) return TRUE;
return FALSE;
}
/**
*
* Status
* returns current state of a task
*
**/
TaskStatus_t Status()
{
TaskStatus_t state ;
m_mutex.Lock();
state = m_state;
m_mutex.Unlock();
return state;
}
void Thread(ThreadId_t *pId)
{
memcpy(pId,&m_dwThread,sizeof(ThreadId_t));
}
CTask(){m_state=TaskStatusNotSubmitted; memset(&m_dwThread,0,sizeof(ThreadId_t)); }
~CTask(){}
virtual BOOL Task()=0;
};
class CThread
#ifdef WINDOWS
: public CObject // use CObject as a base class so object can be used in lists and
// object arrays
#endif
{
private:
CEventClass m_event; // event controller
int m_StopTimeout; // specifies a timeout value for stop
// if a thread fails to stop within m_StopTimeout
// seconds an exception is thrown
BOOL m_bRunning; // set to TRUE if thread is running
#ifdef WINDOWS
HANDLE m_thread; // thread handle
#else
pthread_t m_thread; // thread handle
#endif
ThreadId_t m_dwId; // id of this thread
LPVOID *m_lppvQueue; // task que
unsigned int m_chQueue; // que depth
unsigned int m_queuePos; // current que possition
LPVOID m_lpvProcessor; // data which is currently being processed
ThreadState_t m_state; // current state of thread see thread state data
// structure.
DWORD m_dwIdle; // used for Sleep periods
ThreadType_t m_type;
DWORD m_stackSize; // thread stack size
#define NO_ERRORS 0
#define MUTEX_CREATION 0x01
#define EVENT_CREATION 0x02
#define THREAD_CREATION 0x04
#define UNKNOWN 0x08
#define ILLEGAL_USE_OF_EVENT 0x10
#define MEMORY_FAULT 0x20
#define EVENT_AND_TYPE_DONT_MATCH 0x40
#define STACK_OVERFLOW 0x80
#define STACK_EMPTY 0x100
#define STACK_FULL 0x200
DWORD m_dwObjectCondition;
BOOL Push(LPVOID lpv);
BOOL Pop();
BOOL Empty();
public:
/**
*
* user definable member functions
*
**/
CMutexClass m_mutex; // mutex that protects threads internal data
virtual BOOL OnTask(LPVOID lpvData); // called when an event occurs
virtual BOOL OnTask(); // called when a time interval has elapsed
CThread(void);
~CThread(void);
#ifdef WINDOWS
#ifdef USE_BEGIN_THREAD
friend unsigned __stdcall _THKERNEL(LPVOID lpvData);
#else
friend DWORD WINAPI _THKERNEL( LPVOID lpvData );
#endif
#else
friend LPVOID _THKERNEL(LPVOID lpvData);
#endif
BOOL FromSameThread();
float PercentCapacity();
void WaitTillExit();
BOOL KernelProcess();
BOOL Event(LPVOID lpvData=NULL);
BOOL Event(CTask *pvTask);
void SetOnStopTimeout(int seconds ) { m_StopTimeout = seconds; }
BOOL SetQueueSize( unsigned int ch );
BOOL Stop();
BOOL Start();
void GetId(ThreadId_t *pId) { memcpy(pId,&m_dwId,sizeof(ThreadId_t)); } // returns thread id
ThreadState_t ThreadState();
BOOL PingThread(DWORD dwTimeout=0);
BOOL AtCapacity();
#ifdef WINDOWS
void SetPriority(DWORD dwPriority=THREAD_PRIORITY_NORMAL);
#else
void SetPriority(DWORD dwPriority=0);
#endif
DWORD GetErrorFlags() { return m_dwObjectCondition; } // returns state of object
void SetThreadType(ThreadType_t typ=ThreadTypeNotDefined,DWORD dwIdle=100);
void SetIdle(DWORD dwIdle=100);
unsigned int GetEventsPending();
static BOOL ThreadIdsEqual(ThreadId_t *p1,
ThreadId_t *p2)
{
#if defined(AS400)||defined(OS400)
return(( memcmp(p1,p2,sizeof(ThreadId_t))==0)?TRUE:FALSE);
#elif defined(VMS) || defined(__NetBSD__)
return (( pthread_equal(*p1,*p2) )?TRUE:FALSE );
#else
return ((*p1 == *p2)?TRUE:FALSE);
#endif
}
static ThreadId_t ThreadId()
{
ThreadId_t thisThreadsId ;
#if defined(AS400) || defined(OS400)
pthread_t thread;
#endif
#ifdef WINDOWS
thisThreadsId = (ThreadId_t)GetCurrentThreadId();
#else
#if defined(AS400) || defined(OS400)
thread = pthread_self();
pthread_getunique_np(&thread,&thisThreadsId);
#elif defined(ALPHA) || defined(DEC) || defined(VMS)
#ifdef VMS
thisThreadsId = pthread_self();
#else
thisThreadsId = pthread_getsequence_np(pthread_self());
#endif
#else
thisThreadsId = pthread_self();
#endif
#endif
return thisThreadsId;
}
};
#endif