2011-06-16 6 views
4

Я создал MutexCondition класса, как этогоPthread замок

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

Проблема заключается в том, что я запер переменный мьютекс в функции getWork(), как этого

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

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

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

+2

Как небольшая рекомендация, если вы можете использовать 'boost :: threads', это действительно упростит вашу жизнь. – GWW

+0

Вы не должны полагаться на журналы, они могут получить буферизацию, в многопоточных журналах enviornments может не отображаться реальная картина. –

+1

1) Поиск «Правило трех». 2) Поиск RAII. 3) Прочтите первое предложение [здесь] (http://stackoverflow.com/questions/6352280/pthread-create-error-in-c/6352434#6352434) 4) Начните использовать boost –

ответ

7

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

Ожидаемое поведение.

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

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

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... 
+0

Хорошо, есть ли какие-либо другие проблемы I нужно беспокоиться, прежде чем я перейду к следующему шагу? Для обратного вызова я устанавливаю вызов как статический и передающий делегат. Внутри статической функции я вызывал локальную функцию для запуска цикла. Я слышал, как люди отмечают материал «Extern C», но это то, что я должен исправить или просто рекомендовать?Заранее спасибо – user800799

+0

Спасибо вашему доброму ответу с полностью объясненными кодами! Я очень благодарен! – user800799

+0

Re: "// Remoed это, поскольку он не является детерминированным, когда он будет напечатан". - Это не совсем так. В большинстве систем, если stdout является терминалом, он буферизируется по строке, поэтому он становится красным после каждой новой строки. Когда stdout не является терминалом (например, трубой), тогда он становится недетерминированным, когда все печатается. Обычно реализация stdio имеет внутреннюю блокировку, так что многопоточные printfs не приводят к каким-либо искажениям данных, но порядок, в котором строки печатаются, не является детерминированным. –

Смежные вопросы