/** * @class vetThread * * @brief Class for Multi-threading processes in VETLib, simplify the * use of threads and it's implemented for Linux and Windows both, * developer doesn't need to implement os-dependent code. * * * @bug NOT FULLY IMPLEMENTED * * @warning NOT FULLY IMPLEMENTED * * @todo NOT FULLY IMPLEMENTED * * * @see * @example ../tests/test_vetThread.cpp * * @version 0.45 * @date 18/09/2005 * @author Alessandro Polo * * **************************************************************************** * VETLib Framework 1.0.2 * Copyright (C) Alessandro Polo 2006 * http://www.ewgate.net/vetlib * ****************************************************************************/ #include "vetDefs.h" #ifndef __VETLIB_VETTHREAD_H__ #define __VETLIB_VETTHREAD_H__ #pragma warning(disable:4065) // warning C4065 @ line 653: switch statement contains 'default' but no 'case' labels #define VETTHREAD_ARRAYSIZE 24 #define VETTHREAD_DONE 0 #define VETTHREAD_HALT1 3 #define VETTHREAD_HALT2 6 #define VETTHREAD_TIMEOUT 5000L // 5 seconds #define VETTHREAD_INFINITE INFINITE // windows definition #define VETRET_THREAD_WAIT_TIMEOUT 15011 //timed out #define VETRET_THREAD_ABANDONED 15012 //object abandoned (check msdn) #define VETTHREAD_DEFAULT 0200L #define VETTHREAD_INITIALIZED 15030 #define VETTHREAD_UNINITIALIZED 15031 // #define VETRET_THREAD_ // #define VETRET_THREAD_ #if defined(sun) || defined(__sun) || defined(linux) || defined(__linux) \ || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__OPENBSD__) || defined(__MACOSX__) \ || defined(__APPLE__) || defined(sgi) || defined(__sgi) //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// Unix (Linux,BSD,Irix,...) /* default PTHREAD: - unbounded - nondetached - default stack (alsi default size) - inheris priority */ #include #include // void usleep(long); #include #include class vetThread { protected: pthread_t* osThread; pthread_attr_t* osThreadAttr; bool secureMode; int status; void exit() { pthread_exit(NULL); } public: vetThread() { INFO("vetThread::vetThread() [CONSTRUCTOR]") secureMode = true; //segmentation fault: if ( pthread_attr_init(osThreadAttr) ) osThreadAttr = NULL; status = VETTHREAD_UNINITIALIZED; } vetThread( void* (*functionCall)(void*), void* ArgumentStructure = NULL) { DEBUGMSG("vetThread::vetThread(..) [CONSTRUCTOR]", functionCall) secureMode = true; status = VETTHREAD_UNINITIALIZED; //segmentation fault: if ( pthread_attr_init(osThreadAttr) ) osThreadAttr = NULL; if ( !pthread_create(osThread, osThreadAttr, functionCall, ArgumentStructure) ) status = VETTHREAD_INITIALIZED; } ~vetThread() { INFO("vetThread::~vetThread() [DECONSTRUCTOR]") if ( status == VETTHREAD_UNINITIALIZED ) return; if (secureMode); { if ( waitProcessEnd(true) == VETRET_OK) delete osThread; } //BUG? delete osThread; } inline pthread_t* dump_PTHREAD() { return osThread; }; VETRESULT run( void* (*functionCall)(void*), void* ArgumentStructure = NULL) { DEBUGMSG("int vetThread::run(..)", functionCall) int ret; ret = pthread_create(osThread, osThreadAttr, functionCall, ArgumentStructure); if ( ret == 0 ) status = VETTHREAD_INITIALIZED; return ret;// compatible with VETRET_OK ! } VETRESULT pause() { INFO("int vetThread::pause()") INFO("int vetThread::pause() is NOT AVAILABLE!") return VETRET_INTERNAL_ERR; } VETRESULT resume() { INFO("int vetThread::resume()") INFO("int vetThread::resume() is NOT AVAILABLE!") return VETRET_INTERNAL_ERR; } VETRESULT terminate(bool cancel = false) { DEBUGMSG("int vetThread::terminate(bool cancel)", cancel) if ( status == VETTHREAD_UNINITIALIZED ) return VETRET_ILLEGAL_USE; pthread_exit(osThread); if (cancel) pthread_cancel(*osThread); return VETRET_OK; } VETRESULT waitProcessEnd(bool closeThread = false) { DEBUGMSG("int vetThread::waitProcessEnd(bool closeThread)", closeThread) if (status == VETTHREAD_UNINITIALIZED) return VETRET_ILLEGAL_USE; if ( !pthread_join(*osThread, NULL) ) return VETRET_INTERNAL_ERR; if ( closeThread ) { int status; pthread_exit(&status); return status; } else return VETRET_OK; } void sleep(int millisec) { usleep(millisec); } int getPriority() { sched_param param; int policy; pthread_getschedparam(*osThread, &policy, ¶m); return param.sched_priority; } VETRESULT setPriority(int priority) { sched_param param; param.sched_priority = priority; return pthread_setschedparam(*osThread, SCHED_OTHER, ¶m); } bool isSameAs(vetThread* dst) { if ( pthread_equal(*osThread, *dst->dump_PTHREAD()) ) return true; return false; } void setSecureMode(bool val = true) { secureMode = val; } bool getSecureMode() { return secureMode; }; /////////////////////////////////////////////////////////////////////////// //CURRENT IMPLEMENTATION ONLY FUNCTIONS VETRESULT sendSignal(int signal = 0) { DEBUGMSG("int vetThread::sendSignal(int signal)", signal); return pthread_kill(*osThread, signal); } // /////////////////////////////////////////////////////////////////////////// }; static pthread_mutex_t myCounterMutex = PTHREAD_MUTEX_INITIALIZER; // static pthread_mutex_t myConditionMutex = PTHREAD_MUTEX_INITIALIZER; // static pthread_cond_t myConditionConditioner = PTHREAD_COND_INITIALIZER; static long globalThreadCount = 0; class vetThreadManager { protected: vetThread** myThreads; int* threadsID; int threadCount; bool secureMode; public: vetThreadManager() { myThreads = new vetThread*[VETTHREAD_ARRAYSIZE]; for (int i = 0; i < VETTHREAD_ARRAYSIZE; i++) myThreads[i] = NULL; secureMode = true; threadCount = 0; } ~vetThreadManager() { if ( secureMode ) { waitThreadCompletition(); delete [] myThreads; return; } delete myThreads; } vetThread* newThread(void * (* functionCall)(void *), void* ArgumentStructure = NULL) { if ( threadCount >= VETTHREAD_ARRAYSIZE ) return NULL; myThreads[threadCount] = new vetThread(functionCall, ArgumentStructure); pthread_mutex_lock( &myCounterMutex); ++globalThreadCount; ++threadCount; pthread_mutex_unlock( &myCounterMutex); return myThreads[threadCount]; } VETRESULT waitThreadCompletition(int threadID = -1) { if (threadID == -1) { for (int i = 0; i < VETTHREAD_ARRAYSIZE; i++) if (myThreads[i] != NULL) pthread_join( *myThreads[i]->dump_PTHREAD(), NULL); return VETRET_OK; } if ( threadID < 0 || threadID >= threadCount ) return VETRET_PARAM_ERR; pthread_join( *myThreads[threadID]->dump_PTHREAD(), NULL); return VETRET_OK; } int getCurrentThreadCount() { return threadCount; }; long getGlobalThreadCount() { return globalThreadCount; }; vetThread* getThread(int index) { if ( index < 0 || index >= threadCount ) return NULL; return myThreads[index]; } }; #elif defined(_WIN32) || defined(__WIN32__) //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// Windows 32 #include #include // #define VETRET_THREAD_ // #define VETRET_THREAD_ /* THREAD_PRIORITY_TIME_CRITICAL 15 THREAD_PRIORITY_HIGHEST 2 THREAD_PRIORITY_ABOVE_NORMAL 1 THREAD_PRIORITY_NORMAL 0 THREAD_PRIORITY_BELOW_NORMAL -1 THREAD_PRIORITY_LOWEST -2 THREAD_PRIORITY_IDLE -15 thread_priority_error_return */ class vetThread { protected: HANDLE myThread; DWORD wdID; DWORD flags; int priority; int status; bool secureMode; public: vetThread() { INFO("vetThread::vetThread() [CONSTRUCTOR]") secureMode = true; myThread = NULL; flags = CREATE_DEFAULT_ERROR_MODE; wdID = -1; status = VETTHREAD_UNINITIALIZED; }; /* vetThread(DWORD WINAPI (* functionCall)(LPVOID), void* ArgumentStructure = NULL) { DEBUGMSG("vetThread::vetThread(..) [CONSTRUCTOR]", functionCall) secureMode = true; flags = CREATE_DEFAULT_ERROR_MODE; wdID = -1; myThread = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)functionCall, ArgumentStructure, flags, &wdID); if ( myThread != NULL) status = VETTHREAD_INITIALIZED; else status = VETTHREAD_UNINITIALIZED; }; */ ~vetThread() { INFO("vetThread::~vetThread() [DECONSTRUCTOR]") if (secureMode) { if ( waitProcessEnd(VETTHREAD_TIMEOUT, true) != VETRET_OK ) terminate(); } }; HANDLE dump_HANDLE() { return myThread; }; /* VETRESULT run(DWORD WINAPI (* functionCall)(LPVOID arg), void* ArgumentStructure = NULL) { DEBUGMSG("int vetThread::run(..)", functionCall) if (functionCall == NULL) return VETRET_OK; myThread = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)functionCall, NULL, flags, &wdID); if ( myThread != NULL) status = VETTHREAD_INITIALIZED; else status = VETTHREAD_UNINITIALIZED; return VETRET_OK; }; */ VETRESULT pause() { INFO("int vetThread::pause()") if ( myThread== NULL ) return VETRET_ILLEGAL_USE; if ( SuspendThread(myThread) != (DWORD)-1 ) return VETRET_OK; else return VETRET_INTERNAL_ERR; }; VETRESULT resume() { INFO("int vetThread::resume()") if ( myThread== NULL ) return VETRET_ILLEGAL_USE; if ( ResumeThread(myThread) != (DWORD)-1 ) return VETRET_OK; else return VETRET_INTERNAL_ERR; }; // for extreme case, dangerous VETRESULT terminate(bool closeThread = false) { DEBUGMSG("int vetThread::terminate(bool closeThread)", closeThread) if ( myThread == NULL ) return VETRET_ILLEGAL_USE; if ( myThread!= NULL ) { DWORD exitcode = 0; if ( GetExitCodeThread(myThread, &exitcode) ) if ( TerminateThread(myThread, exitcode) ) return VETRET_OK; return VETRET_INTERNAL_ERR; } if (closeThread) if ( CloseHandle(myThread) ) { myThread = NULL; return VETRET_OK; } return VETRET_ILLEGAL_USE; }; VETRESULT waitProcessEnd(DWORD millisec = VETTHREAD_TIMEOUT, bool closeThread = false) { DEBUGMSG("int vetThread::waitProcessEnd(..,bool closeThread)", closeThread) if ( myThread == NULL ) return VETRET_ILLEGAL_USE; DWORD res = WaitForSingleObject(myThread, VETTHREAD_TIMEOUT); if ( res == WAIT_OBJECT_0 ) if ( closeThread ) { DWORD exitcode = 0; if ( GetExitCodeThread(myThread, &exitcode) ) ExitThread(exitcode); else return VETRET_INTERNAL_ERR; return VETRET_OK; } else return VETRET_OK; else if ( res == WAIT_TIMEOUT ) return VETRET_THREAD_WAIT_TIMEOUT; else if ( res == WAIT_ABANDONED ) return VETRET_THREAD_ABANDONED; return VETRET_INTERNAL_ERR; }; int getPriority() { if ( myThread== NULL ) return VETRET_ILLEGAL_USE; return GetThreadPriority(myThread); }; VETRESULT setPriority(int priority) { if ( myThread== NULL ) return VETRET_ILLEGAL_USE; if ( SetThreadPriority(myThread, priority) ) return VETRET_OK; return VETRET_INTERNAL_ERR; }; void sleep(int millisec) { Sleep(millisec); }; bool isSameAs(vetThread* dst) { if ( myThread != NULL && myThread == dst->dump_HANDLE() ) return true; return false; }; void setSecureMode(bool val = true) { secureMode = val; }; bool getSecureMode() { return secureMode; }; DWORD getID() { return wdID; }; DWORD getFlags() { return flags; } VETRESULT setFlags(int vetThreadFlags = VETTHREAD_DEFAULT) { if ( myThread != NULL ) return VETRET_ILLEGAL_USE; switch (vetThreadFlags) { default: flags = CREATE_DEFAULT_ERROR_MODE; break; } return VETRET_OK; }; /////////////////////////////////////////////////////////////////////////// //CURRENT IMPLEMENTATION ONLY FUNCTIONS // /////////////////////////////////////////////////////////////////////////// }; static HANDLE hThrd; static HANDLE hMutexCounter; static long globalThreadCount = -1; class vetThreadManager { protected: vetThread** myThreads; int* threadsID; int threadCount; bool secureMode; public: vetThreadManager() { myThreads = new vetThread*[VETTHREAD_ARRAYSIZE]; for (int i = 0; i < VETTHREAD_ARRAYSIZE; i++) myThreads[i] = NULL; hMutexCounter = NULL; hMutexCounter = CreateMutex(NULL, 0, NULL); secureMode = true; threadCount = 0; } ~vetThreadManager() { ReleaseMutex(hMutexCounter); if ( secureMode ) { waitThreadCompletition(); delete [] myThreads; return; } delete myThreads; } /* vetThread* newThread(DWORD WINAPI (* functionCall)(LPVOID), void* ArgumentStructure = NULL) { if ( threadCount >= VETTHREAD_ARRAYSIZE ) return NULL; myThreads[threadCount] = new vetThread(functionCall, ArgumentStructure); // pthread_mutex_lock( &myCounterMutex); ++globalThreadCount; ++threadCount; // pthread_mutex_unlock( &myCounterMutex); return myThreads[threadCount]; } */ VETRESULT waitThreadCompletition(int threadID = -1) { DWORD retVal = 0; if (threadID == -1) { for (int i = 0; i < VETTHREAD_ARRAYSIZE; i++) if (myThreads[i] != NULL) retVal += WaitForSingleObject(myThreads[i]->dump_HANDLE(), VETTHREAD_TIMEOUT); //?? // == WAIT_TIMEOUT return VETRET_OK; } if ( threadID < 0 || threadID >= threadCount ) return VETRET_PARAM_ERR; retVal = WaitForSingleObject(myThreads[threadID]->dump_HANDLE(), VETTHREAD_TIMEOUT); return VETRET_OK; } int getCurrentThreadCount() { return threadCount; }; static long getGlobalThreadCount() { return globalThreadCount; }; vetThread* getThread(int index) { if ( index < 0 || index >= threadCount ) return NULL; return myThreads[index]; } static int getPriority(vetThread* thr) { if ( thr == NULL ) return VETRET_ILLEGAL_USE; return GetThreadPriority(thr->dump_HANDLE()); } static VETRESULT setPriority(vetThread* thr, int priority) { if ( thr== NULL ) return VETRET_ILLEGAL_USE; if ( SetThreadPriority(thr->dump_HANDLE(), priority) ) return VETRET_OK; return VETRET_INTERNAL_ERR; } }; #else //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////// Unknown configuration : compile with minimal dependencies. /* Solaris usa */ #endif //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// #endif //__VETLIB_VETTHREAD_H__ /***************************************************************** USE void* myFunction(void* myArgumentStruct) { if ( myArgumentStruct->arg1 > myArgumentStruct->arg2 ) return myArgumentStruct->data; return NULL; } [..] { vetThread myThread; myThread.run(myFunction, myArgs); } ******************************************************************/ /***************************************************************** USE: typedef struct _MyData { int val1; int val2; } MYDATA, *PMYDATA; DWORD WINAPI myFunction(LPVOID lpParam) { PMYDATA pData; TCHAR msgBuf[255]; size_t cchStringSize; DWORD dwChars; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if( hStdout == INVALID_HANDLE_VALUE ) return 1; // Cast the parameter to the correct data type. pData = (PMYDATA)lpParam; // Print the parameter values using thread-safe functions. StringCchPrintf(msgBuf, 255, TEXT("Parameters = %d, %d\n"), pData->val1, pData->val2); StringCchLength(msgBuf, 255, &cchStringSize); WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL); // Free the memory allocated by the caller for the thread data structure. HeapFree(GetProcessHeap(), 0, pData); return VETRET_OK; } [..] int main() { PMYDATA pData; // Allocate memory for thread data. pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYDATA)); vetThread myThread; myThread.run(myFunction, pData); //or // // vetThread myThread(myFunction, pData); } ******************************************************************/