6

関連するミューテックスを最初にロックせずに pthread_cond_timedwait を呼び出すこと、および pthread_cond_signal を呼び出すときにミューテックス ロックを取得しないことの欠点はありますか?

私の場合、チェックする条件は実際にはありません。Javaのwait(long)およびnotify()と非常によく似た動作が必要です。

ドキュメントによると、「予測できないスケジューリング動作」が発生する可能性があります。それが何を意味するのかわかりません。

サンプル プログラムは、最初にミューテックスをロックしなくても問題なく動作するようです。

4

6 に答える 6

12

最初はOKではありません:

および関数は、条件変数でブロックする必要がありますpthread_cond_timedwait()pthread_cond_wait()それらは、呼び出しスレッドまたは未定義の動作結果によってロックされたミューテックスで呼び出されます。

http://opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html

その理由は、ウェイター リストに安全に追加するために、ロックされているミューテックスに実装が依存する可能性があるためです。また、ミューテックスが保持されていることを最初に確認せずに、ミューテックスを解放したい場合があります。

2番目は気がかりです:

予測可能なスケジューリング動作が必要な場合、そのミューテックスは pthread_cond_signal()or を呼び出すスレッドによってロックされますpthread_cond_broadcast()

http://www.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_signal.html

頭のてっぺんから、ロックを取得せずにシグナルを送ると、スケジューラの動作を台無しにする特定の競合状態が何であるかはわかりません。したがって、未定義のスケジューラの動作がどれほど悪くなるかはわかりません。たとえば、ブロードキャストを使用すると、ウェイターが優先順位でロックを取得できない場合があります(または、特定のスケジューラが通常どおり動作します)。または、ウェイターが「迷子」になる可能性があります。

ただし、通常、条件変数を使用すると、単にシグナルを送るのではなく、条件 (少なくともフラグ) とシグナルを設定する必要があり、そのためにはミューテックスを取得する必要があります。その理由は、それ以外の場合、wait() を呼び出す別のスレッドと並行している場合、wait() または signal() のどちらが勝つかによって、まったく異なる動作が得られるためです。気になるシグナルがすでに発生している場合でも、完全なタイムアウトを待ちます。条件変数のユーザーがそれを望んでいることはめったにありませんが、あなたにとっては問題ないかもしれません。おそらくこれは、「予測不可能なスケジューラの動作」というドキュメントの意味です。突然、タイムスライスがプログラムの動作にとって重要になります。

ところで、Java では、notify() または notifyAll() を行うためにロックが必要です。

このメソッドは、このオブジェクトのモニターの所有者であるスレッドによってのみ呼び出される必要があります。

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#notify()

Java 同期 {/}/wait/notifty/notifyAll の動作は、pthread_mutex_lock/pthread_mutex_unlock/pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast に類似しており、偶然ではありません。

于 2009-06-16T18:42:22.090 に答える
10

Butenhof の優れた "Programming with POSIX Threads" では、3.3.3 章の最後でこれについて説明しています。

基本的に、ミューテックスをロックせずに condvar にシグナルを送ることは、パフォーマンスの最適化の可能性です。シグナルスレッドがミューテックスをロックしている場合、condvar でウェイクしているスレッドは、シグナルスレッドがロックされていても、シグナルスレッドがロックしているミューテックスを即座にブロックする必要があります。待機中のスレッドが使用するデータを変更しません。

「予測不可能なスケジューラの動作」が言及されている理由は、condvar で待機している優先度の高いスレッドがある場合 (別のスレッドが優先度の高いスレッドにシグナルを送ってウェイクアップしようとしている)、他の優先度の低いスレッドが来てロックする可能性があるためです。これにより、condvar が通知されて優先度の高いスレッドが起動されたときに、優先度の低いスレッドがミューテックスを解放するのを待つ必要があります。シグナリング中にミューテックスがロックされている場合、優先度の高いスレッドは、優先度の低いスレッドの前にミューテックスでスケジュールされます。基本的に、優先度の高いスレッドを「目覚めさせる」と、スケジューラー許可します (もちろん、優先度の高いスレッドにシグナルを送る前にミューテックスを待つ必要があるかもしれませんが、それは別の問題です)。

于 2010-02-19T17:51:46.243 に答える
3

ミューテックスと組み合わせた条件変数で待機するポイントは、アトミックに待機に入ってロックを解放することです。つまり、他のスレッドが保護された状態を変更できるようにし、状態変更の通知を再びアトミックに受け取り、ロックを取得します。あなたが説明することは、パイプ、ソケット、シグナル、またはおそらく最も適切なセマフォなど、他の多くの方法で実行できます。

于 2009-06-16T18:43:57.080 に答える
1

これはうまくいくはずです(テストされていないコードに注意してください):

// initialize a semaphore
sem_t sem;
sem_init(&sem,
    0, // not shared
    0  // initial value of 0
    );


// thread A
struct timespec tm;
struct timeb    tp;

const long sec      = msecs / 1000;
const long millisec = msecs % 1000;

ftime(&tp);
tp.time += sec;
tp.millitm += millisec;
if(tp.millitm > 999) {
    tp.millitm -= 1000;
    tp.time++;
}
tm.tv_sec  = tp.time;
tm.tv_nsec = tp.millitm * 1000000;

// wait until timeout or woken up
errno = 0;
while((sem_timedwait(&sem, &tm)) == -1 && errno == EINTR) {
    continue;
}

return errno == ETIMEDOUT; // returns true if a timeout occured


// thread B
sem_post(&sem); // wake up Thread A early
于 2009-06-16T18:44:43.197 に答える
0

条件は、可能な限りミューテックスの外部で通知する必要があります。ミューテックスは、並行プログラミングにおける必要悪です。それらを使用すると競合が発生し、複数のプロセッサを使用することで得られる最大のパフォーマンスがシステムから奪われます。

ミューテックスの目的は、プログラム内の一部の共有変数へのアクセスを保護して、それらがアトミックに動作するようにすることです。シグナル操作がミューテックス内で実行されると、共有データの保護とは関係のない何百もの無関係なマシン サイクルがミューテックスに含まれます。潜在的に、ユーザー空間からカーネルまで呼び出します。

標準の「予測可能なスケジューラの動作」に関するメモは完全に偽物です。

マシンに、予測可能な適切に定義された順序でステートメントを実行させたい場合、そのためのツールは、単一の実行スレッド内でのステートメントの順序付けですS1 ; S2。ステートメントS1は の前に「スケジュール」されていS2ます。

一部のアクションが独立しており、それらのスケジューリング順序が重要ではなく、リアルタイム イベントへのよりタイムリーな応答や複数のプロセッサでの計算など、実現すべきパフォーマンス上の利点があることに気付いた場合に、スレッドを使用します。

複数のスレッド間でスケジューリング順序が重要になる場合、これは優先順位と呼ばれる概念に該当します。優先度は、N 個のステートメントのいずれかが実行されるようにスケジュールされる可能性がある場合に、最初に何が起こるかを解決します。マルチスレッドで注文するためのもう 1 つのツールはキューイングです。イベントは 1 つ以上のスレッドによってキューに入れられ、1 つのサービス スレッドがキューの順序でイベントを処理します。

結論として、 の配置はpthread_cond_broadcast実行順序を制御するための適切なツールではありません。プログラムがすべてのプラットフォームでまったく同じ再現可能な動作を突然持つという意味で、実行順序を予測可能にすることはできません。

于 2013-05-29T17:21:32.727 に答える
-1

「予測不可能なスケジューリング動作」とは、まさにそれを意味します。何が起こるかわかりません。実装もしません。期待どおりに機能する可能性があります。アプリがクラッシュする可能性があります。何年も問題なく動作する可能性がありますが、競合状態によりアプリがサルになります。デッドロックする可能性があります。

基本的に、ドキュメントで指示されていることを実行しない限り、未定義/予測不可能なことが発生する可能性があることをドキュメントが示唆している場合は、それを実行することをお勧めします。そうでなければ、あなたの顔に何かが吹き飛ばされるかもしれません。(そして、コードを本番環境に置くまで爆発しません。さらにイライラするだけです。少なくともそれは私の経験です)

于 2009-06-16T20:02:32.417 に答える