Unknown cause of Segmentation Fault during destruction of a ConcurrentQueue - c++

So I was messing around with a ConcurrentQueue (found here) and I am stumbling upon a Seg Fault during the destruction of the ConcurrentQueue (Seg Faults at line 3397 of concurrentqueue.h). I tried using the queue in multiple other contexts however its is only causing a Seg Fault while being used in this context (Code below.) (Which is making me wonder if my code is causing this).
#ifndef MPSCWORKER_MPSCWORKER_HPP
#define MPSCWORKER_MPSCWORKER_HPP
#include <atomic>
#include <condition_variable>
#include <exception>
#include <memory>
#include <thread>
#include "ConcurrentQueue.h"
template <class Type>
class SinkBase;
class SinkNotRegisteredException;
template <class Type, const unsigned int numOfSinks>
class MPSCWorker{
public:
//Funcs
MPSCWorker();
~MPSCWorker(){
Type msg = {};
//Send an empty msg to the reserved channel to say we're done.
send(msg, numOfSinks + 1);
if(workerThread.joinable())
workerThread.join();
for(int i = 0; i <= numOfSinks + 1; i++){
if(sinks[i].get() != nullptr){
sinks[i].get()->onExit();
}
}
}
void start(){
isThreadRunning.store(true);
workerThread = std::thread(run,
std::ref(workQueue),
std::ref(sinks),
std::ref(isThreadRunning),
std::ref(threadCondVar),
std::ref(threadMutex));
}
int addSink(std::unique_ptr<SinkBase<Type>> &&sink, unsigned int sinkID){
if(!isThreadRunning.load()){
if(sinkID <= numOfSinks + 1){
sinks[sinkID] = std::move(sink);
if(!sinks[sinkID].get()->onInit()){
return -3;
}
} else{
return -1;
}
}else{
return -2;
}
return 0;
}
void send(Type msg, unsigned int sinkID){
workQueue.enqueue(InternalType{msg, sinkID});
threadCondVar.notify_one();
}
private:
//Types
struct InternalType{
Type msg;
unsigned int sinkID;
};
//Vars
std::atomic<bool> isThreadRunning;
std::thread workerThread;
std::condition_variable threadCondVar;
std::mutex threadMutex;
//ID = numOfSinks + 1: reserved
std::unique_ptr<SinkBase<Type>> sinks[numOfSinks + 1];
moodycamel::ConcurrentQueue<InternalType> workQueue;
//Funcs
static void run(moodycamel::ConcurrentQueue<InternalType> &workQueue,
std::unique_ptr<SinkBase<Type>> (&sinks)[numOfSinks + 1],
std::atomic<bool> &isThreadRunning,
std::condition_variable &threadCondVar,
std::mutex &threadMutex){
while(isThreadRunning.load()){
InternalType msg = {};
bool isDequeueSuccess = false;
std::unique_lock<std::mutex> lock(threadMutex);
threadCondVar.wait(lock, [&workQueue, &msg, &isDequeueSuccess](){
isDequeueSuccess = workQueue.try_dequeue(msg);
return isDequeueSuccess;
});
if(msg.sinkID == numOfSinks + 1){
isThreadRunning.store(false);
return;
}
if(sinks[msg.sinkID].get() != nullptr){
sinks[msg.sinkID].get()->onProcess(msg.msg);
}else{
throw SinkNotRegisteredException("Sink ID: " + std::to_string(msg.sinkID)
+ " has not been registered. Use addSink"
"to associate this ID with a Sink before"
"starting the worker.");
}
}
}
};
template <class Type, const unsigned int numOfSinks>
MPSCWorker<Type, numOfSinks>::MPSCWorker(){
isThreadRunning.store(false);
for(unsigned int i = 0; i <= numOfSinks +1; i++){
sinks[i] = nullptr;
}
}
class SinkNotRegisteredException : std::exception{
public:
SinkNotRegisteredException(std::string msg){this->msg = msg;}
const char* what(){return msg.c_str();}
std::string whatStr(){return std::string(msg);}
private:
std::string msg;
};
template <class Type>
class SinkBase{
public:
virtual bool onInit() = 0;
virtual void onExit() = 0;
virtual void onProcess(Type data) = 0;
};
#endif //MPSCWORKER_MPSCWORKER_HPP
Here is an example usage of the code above (I know the code is meant for multi-threaded applications but the example is single threaded for simplicity).
#include <iostream>
#include "MPSCWorker.hpp"
template <class Type>
class PrintSink : public SinkBase<Type>{
public:
virtual bool onInit(){return true;}
virtual void onExit(){}
virtual void onProcess(Type data){std::cout << data << std::endl;}
};
int main(){
MPSCWorker<std::string, 1> worker;
std::unique_ptr<PrintSink<std::string>> sink(new PrintSink<std::string>);
if(sink.get() == nullptr){
return -1;
}
worker.addSink(std::move(sink), 0);
worker.start();
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
return 0;
}
Now the real question is: Is my code causing the Seg Fault? Or is it ConcurrentQueue that is doing something wrong? And in any case, How can this be solved?

Related

undefined reference to vtable (class)

I am getting this error:
Linking CXX executable muse3.exe
driver/libmuse_driver.a(qttimer.obj):qttimer.cpp:(.rdata$.refptr._ZTVN8MusECore10InnerTimerE[.refptr._ZTVN8MusECore10InnerTimerE]+0x0): undefined reference to `vtable for MusECore::InnerTimer'
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** [muse\CMakeFiles\muse.dir\build.make:212: muse/muse3.exe] Error 1
mingw32-make[1]: *** [CMakeFiles/Makefile2:600: muse/CMakeFiles/muse.dir/all] Error 2
mingw32-make: *** [Makefile:151: all] Error 2
I understand that the message is a little unclear and the issue is probably with some method.
Here is my .h file:
#ifndef __QTTIMER_H__
#define __QTTIMER_H__
#include <fcntl.h>
#include <QThread>
#include <QBasicTimer>
#include <QTimerEvent>
#include "timerdev.h"
namespace MusECore {
//---------------------------------------------------------
// QtTimer
//---------------------------------------------------------
class InnerTimer : public QObject {
Q_OBJECT
int writePipe;
long int tickCount;
QBasicTimer timer;
public:
void setupTimer(int fd, int timeoutms);
~InnerTimer();
long int getTick();
bool isRunning() { return timer.isActive(); }
protected:
void timerEvent(QTimerEvent *event);
};
class QtTimer : public Timer, public QThread {
int writePipe;
int readPipe;
bool keepRunning;
InnerTimer *innerTimer;
int timeoutms;
public:
QtTimer();
virtual ~QtTimer();
virtual signed int initTimer(unsigned long init);
virtual long unsigned int setTimerResolution(unsigned long resolution);
virtual long unsigned int getTimerResolution();
virtual long unsigned int setTimerFreq(unsigned long freq);
virtual long unsigned int getTimerFreq();
virtual bool startTimer();
virtual bool stopTimer();
virtual long unsigned int getTimerTicks(bool printTicks=false);
void setFindBestTimer(bool ) { }
private:
virtual void run();
};
} // namespace MusECore
#endif //__QTTIMER_H__
And here is the .cpp file:
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include "qttimer.h"
#ifndef TIMER_DEBUG
#define TIMER_DEBUG 1
#endif
#ifdef _WIN32
#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
#endif
namespace MusECore {
QtTimer::QtTimer()
{
if(TIMER_DEBUG)
fprintf(stderr,"QtTimer::QtTimer(this=%p) called\n",this);
innerTimer = NULL;
timeoutms = 10;
readPipe=-1;
writePipe=-1;
}
QtTimer::~QtTimer()
{
if(TIMER_DEBUG)
fprintf(stderr,"QtTimer::~QtTimer(this=%p) called\n",this);
exit(); // thread exit
}
signed int QtTimer::initTimer(unsigned long)
{
if(TIMER_DEBUG)
printf("QtTimer::initTimer(this=%p)\n",this);
int filedes[2]; // 0 - reading 1 - writing
if (pipe(filedes) == -1) {
perror("QtTimer - creating pipe failed");
exit(-1);
}
#ifndef _WIN32
int rv = fcntl(filedes[1], F_SETFL, O_NONBLOCK);
if (rv == -1)
perror("set pipe O_NONBLOCK");
#endif
if (pipe(filedes) == -1) {
perror("QtTimer - creating pipe1");
exit(-1);
}
writePipe = filedes[1];
readPipe = filedes[0];
return filedes[0];
}
long unsigned int QtTimer::setTimerResolution(unsigned long)
{
return 0;
}
long unsigned int QtTimer::setTimerFreq(unsigned long freq)
{
if (freq > 1000)
freq = 1000;
if (freq < 100)
freq = 100;
timeoutms = 1000/freq;
return 1000/timeoutms;
}
long unsigned int QtTimer::getTimerResolution()
{
return 20;
}
long unsigned int QtTimer::getTimerFreq()
{
return 1000/timeoutms;
}
bool QtTimer::startTimer()
{
QThread::start();
return true;
}
bool QtTimer::stopTimer()
{
QThread::quit();
return true;
}
unsigned long int QtTimer::getTimerTicks(bool /*printTicks*/)
{
if(TIMER_DEBUG)
printf("getTimerTicks()\n");
unsigned long int nn;
if (readPipe==-1) {
fprintf(stderr,"QtTimer::getTimerTicks(): no pipe open to read!\n");
return 0;
}
if (read(readPipe, &nn, sizeof(char)) != sizeof(char)) {
fprintf(stderr,"QtTimer::getTimerTicks(): error reading pipe\n");
return 0;
}
//return nn;
return innerTimer != 0 ? innerTimer->getTick() : 0;
}
void QtTimer::run()
{
//bool keepRunning = true;
innerTimer = new InnerTimer();
innerTimer->setupTimer(writePipe, timeoutms); // make sure it is running in the right thread
exec();
}
void InnerTimer::setupTimer(int fd, int timeoutms)
{
tickCount=0;
writePipe = fd;
timer.start(timeoutms, this);
printf("InnerTimer::setupTimer() started\n");
}
InnerTimer::~InnerTimer()
{
timer.stop();
}
void InnerTimer::timerEvent(QTimerEvent *event)
{
//if (tickCount%1000)
//printf("InnerTimer::timerEvent %ld ++++++++++++++++++++++\n",tickCount);
if (event->timerId() == timer.timerId()) {
tickCount++;
write(writePipe,"t",1);
}
}
long int InnerTimer::getTick()
{
return tickCount;
}
} // namespace MusECore
I have read other posts on this error, and they mostly point to some virtual methods that were not defined. But, to me, it seems that everything is defined properly and I also have the destructor defined.
Can anybody point me out to what is wrong?

Assertion failed on __pthread_mutex_cond_lock_full in a load test

I used the following code to create a timer object in my c++ application running on a debian 8.
class Timer
{
private:
std::condition_variable cond_;
std::mutex mutex_;
int duration;
void *params;
public:
Timer::Timer(void (*func)(void*))
{
this->handler = func;
this->duration = 0;
this->params = NULL;
};
Timer::~Timer(){};
void Timer::start(int duree, void* handlerParams)
{
this->duration = duree;
this->params = handlerParams;
/*
* Launch the timer thread and wait it
*/
std::thread([this]{
std::unique_lock<std::mutex> mlock(mutex_);
std::cv_status ret = cond_.wait_for(mlock,
std::chrono::seconds(duration));
if ( ret == std::cv_status::timeout )
{
handler(params);
}
}).detach();
};
void Timer::stop()
{
cond_.notify_all();
}
};
It works correctly under gdb and under normal conditions, but in a load test of 30 requests or more, it crashes with the assertion :
nptl/pthread_mutex_lock.c:350: __pthread_mutex_cond_lock_full: Assertion `(-(e)) != 3 || !robust' failed.
I don't understand the cause of this assertion. Can anyone help me please ??
Thank you
Basically you have a detached thread that accesses the timer object, so it's likely that you destroyed the Timer object but the thread is still running and accessing it's member(mutex, conditional variable).
The assert itself says, from glibc source code, that the owner of the mutex has died.
Thanks a lot for your comments ! I'll try to change the thread detach, and do the load tests.
This is a MVCE of my problem, which is a part of a huge application.
/**
* \file Timer.hxx
* \brief Definition of Timer class.
*/
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
class Timer
{
private:
std::condition_variable cond_;
std::mutex mutex_;
int duration;
void *params;
public:
Timer(void (*func)(void*));
~Timer();
void (*handler)(void*);
void start(int duree, void* handlerParams);
void stop();
};
/*
* Timer.cxx
*/
#include "Timer.hxx"
Timer::Timer(void (*func)(void*))
{
//this->set_handler(func, params);
this->handler = func;
this->duration = 0;
this->params = NULL;
}
Timer::~Timer()
{
}
void Timer::start(int duree, void* handlerParams)
{
this->duration = duree;
this->params = handlerParams;
/*
* Launch the timer thread and wait it
*/
std::thread([this]{
std::unique_lock<std::mutex> mlock(mutex_);
std::cv_status ret = cond_.wait_for(mlock, std::chrono::seconds(duration));
if ( ret == std::cv_status::timeout )
{
handler(params);
}
}).detach();
}
void Timer::stop()
{
cond_.notify_all();
}
/*
* MAIN
*/
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "Timer.hxx"
using namespace std;
void timeoutHandler(void* params)
{
char* data= (char*)params;
cout << "Timeout triggered !! Received data is: " ;
if (data!=NULL)
cout << data << endl;
}
int main(int argc, char **argv)
{
int delay=5;
char data[20] ="This is a test" ;
Timer *t= new Timer(&timeoutHandler) ;
t->start(delay, data);
cout << "Timer started !! " << endl;
sleep(1000);
t->stop();
delete t;
cout << "Timer deleted !! " << endl;
return 0;
}

Embedding matplotlib in C++

I am reading a message from a socket with C++ code and am trying to plot it interactively with matplotlib, but it seems Python code will block the main thread, no matter I use show() or ion() and draw(). ion() and draw() won't block in Python.
Any idea how to plot interactively with matplotlib in C++ code?
An example would be really good.
Thanks a lot.
You may also try creating a new thread that does the call to the
blocking function, so that it does not block IO in your main program
loop. Use an array of thread objects and loop through to find an unused
one, create a thread to do the blocking calls, and have another thread
that joins them when they are completed.
This code is a quick slap-together I did to demonstrate what I mean about
using threads to get pseudo asynchronous behavior for blocking functions...
I have not compiled it or combed over it very well, it is simply to show
you how to accomplish this.
#include <pthread.h>
#include <sys/types.h>
#include <string>
#include <memory.h>
#include <malloc.h>
#define MAX_THREADS 256 // Make this as low as possible!
using namespace std;
pthread_t PTHREAD_NULL;
typedef string someTypeOrStruct;
class MyClass
{
typedef struct
{
int id;
MyClass *obj;
someTypeOrStruct input;
} thread_data;
void draw(); //Undefined in this example
bool getInput(someTypeOrStruct *); //Undefined in this example
int AsyncDraw(MyClass * obj, someTypeOrStruct &input);
static void * Joiner(MyClass * obj);
static void * DoDraw(thread_data *arg);
pthread_t thread[MAX_THREADS], JoinThread;
bool threadRunning[MAX_THREADS], StopJoinThread;
bool exitRequested;
public:
void Main();
};
bool MyClass::getInput(someTypeOrStruct *input)
{
}
void MyClass::Main()
{
exitRequested = false;
pthread_create( &JoinThread, NULL, (void *(*)(void *))MyClass::Joiner, this);
while(!exitRequested)
{
someTypeOrStruct tmpinput;
if(getInput(&tmpinput))
AsyncDraw(this, tmpinput);
}
if(JoinThread != PTHREAD_NULL)
{
StopJoinThread = true;
pthread_join(JoinThread, NULL);
}
}
void *MyClass::DoDraw(thread_data *arg)
{
if(arg == NULL) return NULL;
thread_data *data = (thread_data *) arg;
data->obj->threadRunning[data->id] = true;
// -> Do your draw here <- //
free(arg);
data->obj->threadRunning[data->id] = false; // Let the joinThread know we are done with this handle...
}
int MyClass::AsyncDraw(MyClass *obj, someTypeOrStruct &input)
{
int timeout = 10; // Adjust higher to make it try harder...
while(timeout)
{
for(int i = 0; i < MAX_THREADS; i++)
{
if(thread[i] == PTHREAD_NULL)
{
thread_data *data = (thread_data *)malloc(sizeof(thread_data));
if(data)
{
data->id = i;
data->obj = this;
data->input = input;
pthread_create( &(thread[i]), NULL,(void* (*)(void*))MyClass::DoDraw, (void *)&data);
return 1;
}
return 0;
}
}
timeout--;
}
}
void *MyClass::Joiner(MyClass * obj)
{
obj->StopJoinThread = false;
while(!obj->StopJoinThread)
{
for(int i = 0; i < MAX_THREADS; i++)
if(!obj->threadRunning[i] && obj->thread[i] != PTHREAD_NULL)
{
pthread_join(obj->thread[i], NULL);
obj->thread[i] = PTHREAD_NULL;
}
}
}
int main(int argc, char **argv)
{
MyClass base;
base.Main();
return 0;
}
This way you can continue accepting input while the draw is occurring.
~~Fixed so the above code actually compiles, make sure to add -lpthread

the magic cout that keep my program alive

I wrote a code to implement spin lock and mutex lock.
There is an interesting but. A magic cout can keep my program alive. If I remove the cout, my program will be sleeping forever. (This only happens in Linux. Windows is doing fine)
Any one have a clue?
#include <pthread.h>
#include <iostream>
#include <queue>
#include <sys/time.h>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define Tcount 10
#define TheLock MutexLock
static inline int TAS(volatile int * ptr) {
unsigned long result;
asm volatile("lock;"
"xchgl %0, %1;"
: "=r"(result), "=m"(*ptr)
: "0"(1), "m"(*ptr)
: "memory");
return result;
}
class SpinLock {
private:
int lock;
pthread_t owner;
public:
SpinLock() {
lock = 0;
}
void getLock() {
while (TAS(&lock) == 1) {
}
owner = pthread_self();
}
void releaseLock() {
if (lock == 0) {
cout << "Spin no lock" << endl;
return;
} else if (owner == pthread_self()) {
owner = NULL;
lock = 0;
} else {
throw runtime_error("Spin can't release");
}
}
};
class MutexLock {
private:
int lock;
pthread_t owner;
queue<pthread_t> q;
SpinLock qLock;
public:
MutexLock() {
lock = 0;
}
void getLock(int id) {
pthread_t self = pthread_self();
cout<<"a"<<endl;// magic cout
if (TAS(&lock) == 0) {
owner = self;
return;
}
qLock.getLock();
q.push(self);
qLock.releaseLock();
while (owner != self) {
}
}
void releaseLock(int id) {
if (lock == 0) {
cout << "Mutex no lock" << endl;
return;
} else if (owner == pthread_self()) {
qLock.getLock();
if (q.empty()) {
owner = NULL;
lock = 0;
} else {
owner = q.front();
q.pop();
}
qLock.releaseLock();
} else {
throw runtime_error("Mutex can't release");
}
}
};
TheLock lock;
int g = 0;
void* run(void* pt) {
int id = (int) pt;
for (int i = 0; i < 10000; i++) {
lock.getLock(id);
//cout<<"Thread "<<id<<" get lock, g="<<g<<endl;
int next = g + 1;
g = next;
//cout<<"Thread "<<id<<" release lock, g="<<g<<endl;
lock.releaseLock(id);
}
return NULL;
}
int main() {
pthread_t th[Tcount];
long mtime, seconds, useconds;
struct timeval start, end;
gettimeofday(&start, NULL);
for (int i = 0; i < Tcount; i++) {
pthread_create(&th[i], NULL, run, (void*) (i+10));
}
for (int i = 0; i < Tcount; i++) {
pthread_join(th[i], 0);
}
gettimeofday(&end, NULL);
seconds = end.tv_sec - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
cout << "g=" << g << endl;
cout << "time=" << mtime << endl;
return 0;
}
You cannot implement a mutex by using the volatile keyword as the operations may not be atomic. This means that the OS might switch to a different thread before the operation has completed.
For mutex you have to use the OS. It is the only thing that knows when threads are being switched.

ReadWrite lock using Boost.Threads (how to convert this simple class)

I am porting some code from windows to Linux (Ubuntu 9.10). I have a simple class (please see below), which uses windows functions to implement simple mutex locking. I want to use Boost.Threads to reimplement this, but that library is new to me.
Can someone point out the changes I need to make to the class below, in order tomuse Boost.Threads instead of the WIN specific functions?
#ifndef __my_READWRITE_LOCK_Header__
#define __my_READWRITE_LOCK_Header__
#include <windows.h>
//Simple RW lock implementation is shown below.
#define RW_READERS_MAX 10
#define RW_MAX_SEMAPHORE_COUNT 10
#define RW_MUTEX_NAME L"mymutex"
#define RW_SEMAPHORE_NAME L"mysemaphore"
class CThreadRwLock
{
public:
CThreadRwLock()
{
InitializeCriticalSection(&m_cs);
m_hSem = CreateSemaphore(0, RW_READERS_MAX, RW_READERS_MAX, 0);
}
~CThreadRwLock()
{
DeleteCriticalSection(&m_cs);
CloseHandle(m_hSem);
}
void AcquireReaderLock()
{
EnterCriticalSection(&m_cs);
WaitForSingleObject(m_hSem, INFINITE);
LeaveCriticalSection(&m_cs);
}
void AcquireWriterLock()
{
EnterCriticalSection(&m_cs);
for(int i = 0; i < RW_READERS_MAX; i++)
{
WaitForSingleObject(m_hSem, INFINITE);
}
LeaveCriticalSection(&m_cs);
}
void ReleaseReaderLock()
{
ReleaseSemaphore(m_hSem, 1, 0);
}
void ReleaseWriterLock()
{
ReleaseSemaphore(m_hSem, RW_READERS_MAX, 0);
}
private:
CRITICAL_SECTION m_cs;
HANDLE m_hSem;
};
class CProcessRwLock
{
public:
CProcessRwLock()
{
m_h = CreateMutex(NULL, FALSE, RW_MUTEX_NAME);
m_hSem = CreateSemaphore(NULL, RW_MAX_SEMAPHORE_COUNT, RW_MAX_SEMAPHORE_COUNT, RW_SEMAPHORE_NAME);
}
~CProcessRwLock()
{
CloseHandle(m_h);
}
void AcquireReaderLock()
{
WaitForSingleObject(m_h, INFINITE);
ReleaseMutex(m_h);
}
void AcquireWriterLock()
{
WaitForSingleObject(m_h, INFINITE);
for(int i = 0; i < RW_READERS_MAX; i++)
{
WaitForSingleObject(m_hSem, INFINITE);
}
ReleaseMutex(m_h);
}
void ReleaseReaderLock()
{
ReleaseSemaphore(m_hSem, 1, 0);
}
void ReleaseWriterLock()
{
ReleaseSemaphore(m_hSem, RW_READERS_MAX, 0);
}
private:
HANDLE m_h, m_hSem;
};
class AutoThreadRwLock
{
public:
AutoThreadRwLock(const bool readlock = true):m_readlock(readlock)
{
if (readlock)
m_lock.AcquireReaderLock();
else
m_lock.AcquireWriterLock();
}
~AutoThreadRwLock()
{
if (m_readlock)
m_lock.ReleaseReaderLock();
else
m_lock.ReleaseWriterLock();
}
private:
AutoThreadRwLock(const AutoThreadRwLock&);
AutoThreadRwLock& operator= (const AutoThreadRwLock& );
CThreadRwLock m_lock ;
bool m_readlock ;
};
class AutoProcessRwLock
{
public:
AutoProcessRwLock(const bool readlock = true): m_readlock(readlock)
{
if (readlock)
m_lock.AcquireReaderLock();
else
m_lock.AcquireWriterLock();
}
~AutoProcessRwLock()
{
if (m_readlock)
m_lock.ReleaseReaderLock();
else
m_lock.ReleaseWriterLock();
}
private:
AutoProcessRwLock(const AutoProcessRwLock&);
AutoProcessRwLock& operator= (const AutoProcessRwLock&);
CProcessRwLock m_lock ;
bool m_readlock ;
};
#endif //__my_READWRITE_LOCK_Header__
I'm not going to re-write all your code for you. However you should look into boost's shared_mutex class.
Also, this question from StackOverflow shows how to use a boost::shared_mutex