2011-06-16 10 views
4

私が作成したMutexConditionクラスはのPthreadロック

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

をファイルと私は

#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ファイルをMutexConditionを拡張WorkHandlerを作成しました

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

問題は、私はこれらの2つのログ・ステートメントを印刷し、ログ・ステートメントすべてのスレッドを見れば、私は、しかし、この

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

ようgetWork()関数でmutex変数をロックしているということであり、私はこれがあると思います問題。私は待ち行列に何も入れていないので、最初のスレッドはシグナルを送るために条件変数を待たなければなりません。しかし、最初のスレッドがロックされ、unlock()関数を呼び出さなかったにもかかわらず、他のスレッドがロックの背後にある領域にどのように入り込むことができるか。

これは正しく動作しているのだろうかと思っていました。あなたが修正する必要があるものを皆さんに見せていただければ幸いです。前もって感謝します。

+2

'boost :: threads'を使うことができるのであれば、ちょっとお勧めしますが、実際にはあなたの人生を単純化します。 – GWW

+0

ログに依存しないでください。マルチスレッド環境でログが実際の画像を表示しない可能性があります。 –

+1

1) "3のルール"を参照してください。 2)RAIIを検索する。 3)最初の文[ここをクリック]を読む(http://stackoverflow.com/questions/6352280/pthread-create-error-in-c/6352434#6352434)4)ブーストの使用を開始 –

答えて

7

なぜなら、スレッドが条件変数を待つとき、mutexはロックされていないからです。

これは予想される動作です。

条件変数が通知されると、ロックが再度取得されるまで、スレッドは解放されずに実行されます。

あなたはこれに機能を変更する場合:私は期待する信号をコールするたびに

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 
あなたは、私が期待する3つのスレッドを作成した場合

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

信号をどれくらい速く呼び出しても、私はいつもこの2つが順番に印刷されることを期待しています。
ロックが再取得されるまで、スレッドは条件変数から解放されないためです。

ご覧になる場合があります。

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

Ok ..他にも問題があります。私は次のステップに移る前に懸念する必要がありますか?コールバックの場合は、コールを静的に設定してデリゲートを渡します。静的関数の内部では、ループを実行するローカル関数を呼び出しました。私は人々が「Extern C」のものを指摘していると聞いてきましたが、これを解決しなければならない、あるいはちょっとお勧めするべきことは何ですか?事前に感謝 – user800799

+0

完全に説明されたコードであなたの種類の答えをありがとう!私は本当に感謝しています! – user800799

+0

Re: "//印刷時に非決定論的なので、これを再現しました。" - それは事実ではありません。ほとんどのシステムでは、stdoutが端末であれば、それはバッファされているので、改行ごとにフラッシュされます。 stdoutが端末(例えば、パイプ)でないときは、物事が印刷されるときに非確定的になる。 stdioの実装では通常、内部ロックがあるので、マルチスレッドのprintfsはデータの破損を引き起こすことはありませんが、文字列の出力順序は非決定論的です。 –

関連する問題