I have created MutexCondition class like this
/*MutexCondtion.h file*/
#ifndef MUTEXCONDITION_H_
#define MUTEXCONDITION_H_
#include <pthread.h>
#include <stdio.h>
class MutexCondition {
private:
bool init();
bool destroy();
protected:
pthread_mutex_t m_mut;
pthread_cond_t m_con;
public:
MutexCondition(){
init();
}
virtual ~MutexCondition(){
destroy();
}
bool lock();
bool unLock();
bool wait();
bool signal();
};
#endif /* MUTEXCONDITION_H_ */
MutexCondtion.cpp file
#include "MutexCondition.h"
bool MutexCondition::init(){
printf("MutexCondition::init called\n");
pthread_mutex_init(&m_mut, NULL);
pthread_cond_init(&m_con, NULL);
return true;
}
bool MutexCondition::destroy(){
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&m_con);
return true;
}
bool MutexCondition::lock(){
pthread_mutex_lock(&m_mut);
return true;
}
bool MutexCondition::unLock(){
pthread_mutex_unlock(&m_mut);
return true;
}
bool MutexCondition::wait(){
pthread_cond_wait(&m_con, &m_mut);
return true;
}
bool MutexCondition::signal(){
pthread_cond_signal(&m_con);
return true;
}
And I created a WorkHandler which extends the MutexCondition
#ifndef WORKHANDLER_H_
#define WORKHANDLER_H_
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <list>
#include "MutexCondition.h"
#include "Work.h"
using namespace::std;
class WorkHandler: MutexCondition {
private:
int m_maxThreads;
queue<Work*> m_workQueue;
list<pthread_t*> m_workThreadList; //Just thread IDs
pthread_t **m_workThreads;
void workLoop();
bool initThreads();
void insertWork(Work *work);
Work* getWork();
protected:
static void* runWorkThread(void* delegate);
public:
WorkHandler(int maxThreads);
virtual ~WorkHandler();
};
#endif /* WORKHANDLER_H_ */
WorkHandler.cpp file
#include "WorkHandler.h"
WorkHandler::WorkHandler(int maxThreads) {
// TODO Auto-generated constructor stub
m_maxThreads = maxThreads;
initThreads();
}
WorkHandler::~WorkHandler() {
// TODO Auto-generated destructor stub
}
void* WorkHandler::runWorkThread(void *delegate){
printf("WorkHandler::runWorkThread called\n");
WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
ptr->workLoop();
return NULL;
}
void WorkHandler::workLoop(){
printf("WorkHandler::workLoop called\n");
//WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
while(1){
Work *work = getWork();
}
}
bool WorkHandler::initThreads(){
for(int i=0; i < m_maxThreads; i++){
pthread_t *thread(new pthread_t);
m_workThreadList.push_back(thread);
if(pthread_create(thread, NULL, runWorkThread, reinterpret_cast<void *>(this))!=0){
perror("InitThreads, pthread_create error \n");
return false;
}
pthread_detach(*thread);
}
return true;
}
void WorkHandler::insertWork(Work* w){
printf("WorkHandler::Thread %d insertWork locking\n", pthread_self());
lock();
printf("WorkHandler::insertWork Locked and inserting int queue \n");
m_workQueue.push(w);
signal();
unLock();
}
Work* WorkHandler::get开发者_开发技巧Work(){
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
The problem is that I have locked the mutex variable in the getWork() function like this
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
However, if I see the log statements then all threads printed these two log statements and I think this is a problem. I am not putting anything into the queue so the first thread should wait the condition variable to be signaled and it works ok. But how come other thread can enter the area behind the lock although the first thread locked and has not called the unlock() function.
I was wondering if this is working correctly. Pleas let me know if you guys can see anything I need to fix. Thanks in advance.
The reason is that that when a thread waits on a condition variable the mutex is unlocked.
This is expected behavior.
When the condition variable is signaled the thread is not released to run until the lock is re-acquired.
If you change the function to this:
Work* WorkHandler::getWork(){
// Remoed this as it is non-determinstic when it will be printed.
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
printf("WorkHandler::getWork waiting DONE\n"); // Added this.
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
If you then created three threads I would expect:
WorkHandler::getWork locked
WorkHandler::getWork waiting...
WorkHandler::getWork locked;
WorkHandler::getWork waiting...
WorkHandler::getWork locked
WorkHandler::getWork waiting...
For each call to signal I would expect:
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork waiting DONE
WorkHandler::getWork got a job
No matter how fast you call signal I would always expect to see these two printed in order.
Because the thread is not released from the condition variable until it has re-acquired the lock.
Note you may see.
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork locked // A previously released thread finishes and steals
// the job before the signalled thread can aquire the lock.
WorkHandler::getWork got a job
WorkHandler::getWork waiting DONE // Now the released thread just goes back to waiting.
WorkHandler::getWork waiting...
精彩评论