I'm writing a multithreaded application. At the moment I use mutexes to protect data shared between threads. Everything works so far, but I believe I'm wasting quite a lot of CPU time in lockstates.
The problem is that whenever I access a global variable, I have to lock it, even when I'm just going to read from it. If I would only lock on writes, multiple writes at the same time would be prevented, but I could still read during a write, which is just as bad.
So I need some mechanism to lock data in a way that multiple reads can take place at the same time, but no two writes or reads and writes. I have come up with a sollution using three mutexes, but that pretty much looks like overkill.
This whole thing sounds so much like a standard situation that I'm wondering why there is no standard sollution to it... or rather why I can't find it. Any links or suggestions are really welcome. Thanks
This is my current code (using pthreads, but I wouldn't mind windows code either). It's giving preference to write attempts, preventing the start of more reads as soon as one thread tries to write.
Code:
#include <pthread.h>
typedef struct {
pthread_mutex_t tRead;
pthread_mutex_t tWrite;
pthread_mutex_t tInternal;
int iRefCount;
} TCritSect, *PCritSect;
typedef enum {
kCritSectRead,
kCritSectWrite
} ECritSectMode;
void CritSectInit(PCritSect *ptCS) {
pthread_mutex_init(&ptCS->tRead, NULL);
pthread_mutex_init(&ptCS->tWrite, NULL);
pthread_mutex_init(&ptCS->tInternal, NULL);
ptCS->iRefCount= 0;
}
void CritSectDeinit(PCritSect *ptCS) {
pthread_mutex_destroy(&ptCS->tRead);
pthread_mutex_destroy(&ptCS->tWrite);
pthread_mutex_destroy(&ptCS->tInternal);
}
void CritSectLock(PCritSect *ptCS, ECritSectMode eCSMode) {
pthread_mutex_lock(&ptCS->tWrite);
if (eCSMode == kCritSectRead) {
pthread_mutex_lock(&ptCS->tInternal);
if (ptCS->iRefCount == 0)
pthread_mutex_lock(&ptCS->tRead);
iRefCount++;
pthread_mutex_unlock(&ptCS->tInternal);
pthread_mutex_unlock(&ptCS->tWrite);
return;
}
else {
pthread_mutex_lock(&ptCS->tRead);
return; // leave tWrite and tRead locked
}
}
void CritSectUnlock(PCritSect *ptCS, ECritSectMode eCSMode) {
if (eCSMode == kCritSectRead) {
pthread_mutex_lock(&ptCS->tInternal);
iRefCount--;
if (ptCS->iRefCount == 0)
pthread_mutex_unlock(&ptCS->tRead);
pthread_mutex_unlock(&ptCS->tInternal);
}
else {
pthread_mutex_unlock(&ptCS->tWrite);
pthread_mutex_unlock(&ptCS->tRead);
}
}