0

私のプログラムには、タスクを待機してファイルに出力するデーモンスレッドがあります。その機能は次のとおりです。

void * deamon(void *) {
    while(true) {
        pthread_mutex_lock(manager->getLock());
        while(!manager->isPending()) {
            if (manager->isClosing()) {
                pthread_exit(NULL);
            }
            pthread_cond_wait(manager->getCond(), manager->getLock());
            //check that condition if met - surprises may occur!
        }
                //WRITE TO FILE HERE
        pthread_mutex_unlock(manager->getLock());
    }
    return NULL;
}

ご覧のとおり、保留中のタスクがない場合、デーモンは新しいタスクを待機します。新しいものを入手したら、それを別のクラスのデータベースにプッシュし(デーモンはクラスにありません)、次のようにシグナルを送信します。

void Manager::pushNewTask(Task * task) {
    pthread_mutex_lock(_lock);
    map<int,Task *>::iterator it = _tasks->end();
    _tasks->insert(it,make_pair(task->getId(),task));
    // At the first time a signal is sent with no need
    if (_tasks->size() == 1) {
        _pending = true;
        pthread_cond_signal(_cond); //SEND SIGNAL TO DAEMON THREAD
    }
    pthread_mutex_unlock(_lock);
}

3つの質問:

  1. ここのコードからは明らかではありませんが、両方とも同じオブジェクトdaemon()を使用しています-それは問題ではありませんか?デーモンがスリープ(待機)すると、ミューテックスのロックは解除されません。pushNewTask()pthread_mutex_t
  2. 複数の機能が同じものでロックされているとはどういう意味pthread_mutex_lockですか?たぶん、1つのスレッドだけがそれらのいずれかにアクセスできますか?いつ違うものを使うべきpthread_mutex_t objectsですか?

ありがとう

4

1 に答える 1

3

1: ここのコードからは明らかではありませんが、daemon() と pushNewTask() の両方が同じ pthread_mutex_t オブジェクトを使用しています - それは問題ではありませんか?

pthread_cond_wait(manager->getCond(), manager->getLock());

いいえ、これは問題ではありません。への呼び出しpthread_cond_wait()は、ロックを解放し、スレッドを中断します。条件変数が通知されたとき。スレッドはロックを再取得し、呼び出しから に戻りますpthread_cond_wait()。したがって、スレッドが実行されている間はロックが保持され、スレッドがスリープしている間はロックが解放されます (別のスレッドがミューテキストのロックを保持している場合、スレッドは終了できないことに注意してくださいpthread_cond_wait())。

2: 複数の関数が同じ pthread_mutex_lock でロックされているとはどういう意味ですか? たぶん、1 つのスレッドだけがそれらのいずれかにアクセスできますか? 別の pthread_mutex_t オブジェクトをいつ使用する必要がありますか?

いいえ。常に同じミューテックス/条件変数のペアを使用する必要があります。また、オブジェクト (この場合はオブジェクト) へのアクセスManagerは、通常、単一のロックによって制御されます。これは、ロックを保持しているスレッドのみが manager オブジェクト内のコードを実行できることを意味します (したがって、一度に 1 つのスレッドのみ)。「条件変数」で一時停止されたスレッドはロックを解放するため、他のスレッドは一時停止中に動作できますが、マネージャーでコードを実行できるようになる前にロックを再取得する必要があります。

より良い使用法:

pthread_cond_wait(manager->getCond(), manager->getLock());

これは、競合状態の影響を非常に受けやすくなっています。次のように記述します。

while(<No Tasks available>)
{
    pthread_cond_wait(manager->getCond(), manager->getLock());
}

参照:親を待機するスレッド

エラー:

        if (manager->isClosing()) {
            pthread_exit(NULL);
        }

これは問題です。ミューテックスのロックを保持したまま、スレッドが死んでいます。スレッドが死ぬ前に、ミューテックスを解放する必要があります。できれば、ミューテックスは RAII を介して制御する必要があります。これにより、その使用が例外セーフになり、pthread_exit() を呼び出すのではなく、関数から戻ることでスレッドを終了できます。

pthread_exit() の使用は、通常のアプリケーションで exit() を呼び出すのと同じです。スタック上の自動オブジェクトが正しく破棄されないため、これは良い考えではありません。これは C++ コードで問題になる可能性があるため、pthread_exit() の使用は推奨されません。代わりに、スレッドを開始した元の関数からスレッドが戻ることを許可して、スレッドを自然に終了させる必要があります。(PS は、スレッド スタックを最後までアンワインドする例外をスローしません。例外が原因でスレッドが終了したときに pthreads が行うことは未定義です (私が見たほとんどのシステムでは、これによりアプリケーションが終了します))。

于 2012-05-07T19:37:57.217 に答える