Pthread Lock

I created a 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 that extends 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::getWork(){ 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 locked the mutex variable in getWork () function like this

  printf("WorkHandler::getWork locking\n"); lock(); printf("WorkHandler::getWork locked\n"); 

However, if I see the log instructions, then all the threads printed these two log statements, and I think this is the problem. I do not put anything in the queue, so the first thread should wait for the condition variable, which should be signaled, and it works fine. But why another thread can enter the area behind the lock, although the first thread is blocked and did not call the unlock () function.

I was wondering if this worked correctly. Please let me know if you guys can see everything I need to fix. Thanks in advance.

+4
source share
1 answer

The reason is that when a thread expects a condition variable, the mutex is unlocked.

This is the expected behavior.

When the condition signaling is signaled, the thread is not freed to start 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 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 every signal call, 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 trigger the signal, I always expect to see these two printed in order.
Because the thread is not exempted from the condition variable until it restores the lock.

Notice what you can 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... 
+7
source

All Articles