web-dev-qa-db-ja.com

pthreadを一時停止および再開するための最良の解決策は何ですか?

Pthreadについて次のトピック( ここ )を見つけましたが、多くの良い解決策があります。

次のコードが有効かどうか、有効な場合は、同じロックを使用して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);
}

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

12
Chef Pharaoh

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

このコードを見てください-ミューテックスは何を保護していますか?サスペンド/レジューム状態を保護するものは何ですか?

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

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

8
David Schwartz

これが正しい方法です。 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が行うことです。
3
ybungalobill

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

はい。

もしそうなら、なぜ同じロックが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を一時停止する正しい方法ですか?

私が思う他のどれよりも良い。

1
Martin York