• Content count

  • Joined

  • Last visited

Community Reputation

122 Neutral

About crawfis

  • Rank
  1. Multithreading (with DevIL)

    Here is some C++ code that uses pThreads and MS Critical section. For C, encapsulate a separate _lock variable for each logic chunk of global memory you want to protect. Also hide the lock call and access to the _lock variable behind your encapsulated global variable. Except for the constructors, everything else is just a facade over the existing system support. FYI, I am a Professor of Computer Science at The Ohio State University and do not usually check the forums. Some students were having some problems with DevIL, so I noticed your plea for help there. Great library so hopefully this is giving back a little. Roger -------------------Warning - student code below ------------------- #ifndef _H_CRITICAL_SECTION #define _H_CRITICAL_SECTION #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> #else #include <pthread.h> #include <errno.h> #include <iostream> //Prefer non-portable (NP) recursive mutex if available #ifdef PTHREAD_MUTEX_RECURSIVE_NP #define PTHREAD_RECURSIVE_MUTEX_TYPE PTHREAD_MUTEX_RECURSIVE_NP #else #define PTHREAD_RECURSIVE_MUTEX_TYPE PTHREAD_MUTEX_RECURSIVE #endif #endif //============================================================= // Class Declaration //============================================================= class CriticalSection { public: CriticalSection(); ~CriticalSection(); //NOTE: non-virtual destructor! void lock(); void unlock(); bool tryLock(); //attempt to lock, return false on failure #ifdef _WIN32 private: CRITICAL_SECTION _lock; HANDLE _currentThread; #else private: pthread_mutex_t _lock; #endif }; //============================================================= // Inline Implementations //============================================================= #ifdef _WIN32 // // WIN32 // inline CriticalSection::CriticalSection() { InitializeCriticalSection(&_lock); } inline CriticalSection::~CriticalSection() { DeleteCriticalSection(&_lock); } inline void CriticalSection::lock() { EnterCriticalSection(&_lock); } inline void CriticalSection::unlock() { LeaveCriticalSection(&_lock); } inline bool CriticalSection::tryLock() { return (TryEnterCriticalSection(&_lock) != 0); } #else // // PTHREADS // inline CriticalSection::CriticalSection() { pthread_mutexattr_t attr = {0}; //memset(&attr, 0, sizeof(attr)); #ifndef CRITICAL_SECTION_TEST pthread_mutexattr_settype(&attr, PTHREAD_RECURSIVE_MUTEX_TYPE); pthread_mutex_init(&_lock, &attr); #else //Check for mutex initialization failure... (incurs minor overhead) int result = pthread_mutexattr_settype(&attr, PTHREAD_RECURSIVE_MUTEX_TYPE); if(result != 0) { switch(result) { case EINVAL: std::cout << "pthread_mutexattr_settype() failed with resultCode=EINVAL\n"; break; case EFAULT: std::cout << "pthread_mutexattr_settype() failed with resultCode=EFAULT\n"; break; default: char buff[255]; sprintf(buff, "pthread_mutexattr_settype() failed with unrecognized resultCode=%i\n", result); std::cout << buff; break; } } result = pthread_mutex_init(&_lock, &attr); if(result != 0) { switch(result) { case EAGAIN: std::cout << "pthread_mutex_init() failed with resultCode=EAGAIN\n"; break; case ENOMEM: std::cout << "pthread_mutex_init() failed with resultCode=ENOMEM\n"; break; case EPERM: std::cout << "pthread_mutex_init() failed with resultCode=EPERM\n"; break; case EBUSY: std::cout << "pthread_mutex_init() failed with resultCode=EBUSY\n"; break; case EINVAL: std::cout << "pthread_mutex_init() failed with resultCode=EINVAL\n"; break; default: char buff[255]; sprintf(buff, "pthread_mutex_init() failed with unrecognized resultCode=%i\n", result); std::cout << buff; break; } } } inline CriticalSection::~CriticalSection() { pthread_mutex_destroy(&_lock); } inline void CriticalSection::lock() { pthread_mutex_lock(&_lock); } inline void CriticalSection::unlock() { pthread_mutex_unlock(&_lock); } inline bool CriticalSection::tryLock() { return pthread_mutex_trylock(&_lock); } #endif #endif _H_CRITICAL_SECTION
  2. Multithreading (with DevIL)

    There is a lot of misguided advice on concurrent programming, so be wary of the web. The best way to achieve robust multi-threading is to make sure your software architecture is sound. Except for the global vars, everything seems fine. It also seems like these variables should indeed be global, which means having different instances per thread is not what you want. 1) Make the global variables encapsulated with proceedures. 2) On access to these variables, place a lock (mutex, Critical Section, etc.), copy the values out or set the values and then unlock. If you can copy the data over then things are much safer. Things to avoid: a) avoid locks everywhere. By placing a single lock in the encapsulated method that makes no calls back out to the system (or itself) you avoid the possibility of deadlock. Immutable data structures are a parallel programmers dream. b) Worrying about performance. The performance warnings usually come from systems people who worry about microseconds and view the world as constantly calling locks. For your situation it seems that you rarely will call a lock, so it is a non-issue. Note, for the Win32 critical section, if the lock is not currently held it boils down to a no-op. Hence it is very very fast. Contention for locks will always cause performance problems, so it is best to limit the contention. The above should do that. For the encapsulation, Object oriented would help (as would the Singleton Design Pattern), but you can get by with a single point of entry (a C function). Protect your data and you should be okay.