Блокировка - PullRequest
       4

Блокировка

4 голосов
/ 16 июня 2011

Я создал класс MutexCondition, подобный этому

/*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

#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;
}

И я создал WorkHandler, который расширяет 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

#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;
}

Проблема в том, что я заблокировал переменную mutex в функции getWork () следующим образом

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

Однако, если я вижу операторы журнала, тогда всеТемы напечатали эти два оператора журнала, и я думаю, что это проблема.Я не помещаю ничего в очередь, поэтому первый поток должен ждать, пока переменная условия будет сигнализирована, и она работает нормально.Но почему другой поток может войти в область за блокировкой, хотя первый поток заблокирован и не вызвал функцию unlock ().

Мне было интересно, работает ли это правильно.Пожалуйста, дайте мне знать, если вы, ребята, сможете увидеть что-нибудь, что мне нужно исправить.Заранее спасибо.

1 Ответ

7 голосов
/ 16 июня 2011

Причина в том, что когда поток ожидает переменную условия, мьютекс разблокируется.

Это ожидаемое поведение.

Когда сигнализируется переменная условия, поток не освобождается дляработать до тех пор, пока блокировка не будет восстановлена.

Если вы измените функцию следующим образом:

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;
}

Если бы вы создали три потока, я бы ожидал:

WorkHandler::getWork locked
WorkHandler::getWork waiting...
WorkHandler::getWork locked;
WorkHandler::getWork waiting...
WorkHandler::getWork locked
WorkHandler::getWork waiting...

Для каждого вызова к сигналу я ожидал бы:

WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork waiting DONE
WorkHandler::getWork got a job

Независимо от того, как быстро вы вызываете сигнал, я всегда ожидал бы, что эти два будут напечатаны по порядку.
Поскольку поток не освобождается от условияпеременная, пока не получит блокировку заново.

Обратите внимание, что вы можете видеть.

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...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...