13

pthreads に関する次のトピック ( here ) を見つけましたが、多くの優れた解決策があります。

次のコードが有効かどうか、有効な場合は、同じロックを使用して pthread_cond_wait を呼び出し、アクセスしてすぐにロックを解除する理由を知りたいと思いました。

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

ここで 2 つの別個のミューテックスを使用する方がよいのではないでしょうか?それとも、これが pthread を一時停止する正しい方法ですか??

前もって感謝します!

編集:

すばらしい回答、ありがとうございました。関連する質問をもう 1 つだけ。別の関数でスレッドを個別に再開したいので、再開するにはこちらの方が適切でしょうか?

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
    pthread_cond_signal(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}

みんなありがとう!:~)

4

3 に答える 3

8

実際、このコードはスレッドセーフではありません。ミューテックスは実際には何も保護していないため、暗黙の述語が競合状態に対して脆弱なままになっています。

このコードを見てください -- ミューテックスは何を保護していますか? 中断/再開状態を保護するものは何ですか?

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
    pthread_cond_signal(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}

正解です:

void suspendMe()
{ // tell the thread to suspend
    pthread_mutex_lock(&m_SuspendMutex);
    m_SuspendFlag = 1;
    pthread_mutex_unlock(&m_SuspendMutex);
}
void resumeMe()
{ // tell the thread to resume
    pthread_mutex_lock(&m_SuspendMutex);
    m_SuspendFlag = 0;
    phtread_cond_broadcast(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}
void checkSuspend()
{ // if suspended, suspend until resumed
    pthread_mutex_lock(&m_SuspendMutex);
    while (m_SuspendFlag != 0) pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

スレッドはcheckSuspend、中断できる安全なポイントで呼び出す必要があります。suspendMe他のスレッドは、 およびを呼び出してresumeMe、スレッドを一時停止/再開できます。

ミューテックスがm_SuspendFlag変数を保護し、スレッドが中断するように指示され、再開するように指示され、保護下で中断するか中断したままにするかを確認し、コードをスレッドセーフにすることに注意してください。

ここで 2 つの別個のミューテックスを使用する方がよいのではないでしょうか?それとも、これが pthread を一時停止する正しい方法ですか??

2 つのミューテックスを使用すると、条件変数のポイント全体が無効になります。それらが機能する全体的なメカニズムは、待機する必要があるものがあるかどうかを確認し、待機中にロックを保持したり、ロックを解放して待機したりすることなく、アトミックに待機できることです。待機中にロックを保持している場合、他のスレッドはどのように状態を変更できますか? また、ロックを解除してから待機した場合、状態の変更を見逃した場合はどうなりますか?

ところで、スレッドを一時停止または再開することはほとんど意味がありません。外部からスレッドを一時停止する必要があると感じた場合、それは、実際にはやりたくないことを実行するようにスレッドをコーディングしたことを示しています。スレッドの一時停止または再開に関する質問は、多くの場合、スレッド プログラミングのメンタル モデルが正しくないことを示しています。スレッドは何かを待つ必要があるかもしれませんが、外部から「一時停止」されるべきではありません。なぜなら、スレッドは特定の作業を行うべきではないことを独自のコーディングによって既に知っているはずだからです。

于 2012-12-01T19:36:20.797 に答える
4

これが正しい方法です。pthread_cond_wait ロックを解除 m_SuspendMutexし、待機してから、戻る前に再度m_ResumeCondロックします。m_SuspendMutex

このように動作する理由は、条件変数が何らかの状態の変化を通知するために使用され、この状態が共有されているため、一部のスレッドがアクセスしている間はロックする必要があるためです。たとえば、イベントのキューを実装することを検討してください。

T get_item()
{
    pthread_mutex_lock(&mutex);
    while(qu.empty())
        pthread_cond_wait(&cond, &mutex);
    T ret = qu.front();
    qu.pop();
    pthread_mutex_unlock(&mutex);
    return ret; // we got an item from a queue
}

void add_item(T x)
{
    pthread_mutex_lock(&mutex);
    qu.push(x);
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cond);
}

ご了承ください:

  1. キューへのすべてのアクセスquは、mutex.
  2. 条件変数を待機するときはmutex、他のスレッドがアイテムをキューに追加できるようにロックを解除する必要があります。変数が変更されたら、mutex実際にキューを検査するために再度ロックする必要があります。これはまさに何をするかpthread_cond_signalです。
于 2012-12-01T19:11:28.627 に答える
1

次のコードが有効かどうか知りたかった

はい。

もしそうなら、同じロックが pthread_cond_wait の呼び出しとそれにアクセスするために使用され、すぐにロック解除される理由:

pthread_cond_wait()は、ロックされたミューテックスが必要です。これは、条件変数の使用方法によるものです。通常、これらは次のように使用されます。

pthread_mutex_lock(&m_SuspendMutex);
while (!ready())
{
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}

// Modify the resources protexted by the lock.
pthread_mutex_unlock(&m_SuspendMutex);

したがって、ロックによって保護されているリソースを変更したいと言ってロックを取得します。ただし、オブジェクトがready()状態にない場合pthread_cond_wait()は、スレッドを中断してミューテックスのロックを解除するスレッドを中断します (したがって、他のスレッドがロックを取得し、オブジェクトをready()状態に変換できる可能性があります)。

準備完了状態になるm_ResumeCondと、シグナルが送信され、待機中のスレッドが一時停止から解放されます。ただし、終了を許可する前にpthread_cond_wait()、ロックを再取得しm_SuspendMutexて、ミューテックスによって保護されたリソースを変更する唯一のスレッドであることを確認する必要があります。

上記がアトミックな方法 (ロック解除/サスペンド/再開/ロック) で正しく行われていることを確認するには、 pthread_cond_wait().

ここで 2 つの別々のミューテックスを使用する方がよいのではないでしょうか

いいえ。

または、これは pthread を一時停止する正しい方法ですか??

私が思う他のものと同じくらい良い。

于 2012-12-01T19:14:15.657 に答える