pthread_cond_timedwaitおよびpthread_cond_signalのmutexをロックしない(Linuxの場合)
-
05-07-2019 - |
質問
関連するミューテックスを最初にロックせずにpthread_cond_timedwaitを呼び出すことと、pthread_cond_signalを呼び出すときにミューテックスロックを取得しないことのマイナス面はありますか?
私の場合、実際に確認する条件はありません。Javawait(long)およびnotify()に非常によく似た動作が必要です。
ドキュメントによると、「予測不可能なスケジューリング動作」が発生する可能性があります。意味がわかりません。
最初にミューテックスをロックしなくても、サンプルプログラムは正常に動作するようです。
解決
最初は大丈夫ではありません:
pthread_cond_timedwait()
およびpthread_cond_wait()
関数は 条件変数でブロックします。彼ら mutexをロックして呼び出します 呼び出しスレッドまたは未定義 動作結果。
http://opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html
その理由は、ウェイターリストに安全に追加するために、実装がロックされているミューテックスに依存する場合があるためです。そして、最初に保持されていることを確認せずにミューテックスを解放したい場合があります。
2番目は不安です:
予測可能なスケジューリング動作が 必要な場合、そのミューテックスは 呼び出し元のスレッド
pthread_cond_signal()
またはpthread_cond_broadcast()
。
http://www.opengroup.org/onlinepubs/007908775/xsh/ pthread_cond_signal.html
私の頭上では、ロックを取得せずに信号を送るとスケジューラの動作を台無しにする特定の競合状態が何なのかわかりません。したがって、未定義のスケジューラの動作がどれほど悪いのかはわかりません。たとえば、ブロードキャストでは、ウェイターが優先順位でロックを取得しません(または、特定のスケジューラが通常動作する場合)。または、ウェイターが「迷子になる」可能性があります。
ただし、一般に、条件変数を使用して、単なるシグナルではなく、条件(少なくともフラグ)とシグナルを設定します。このためには、ミューテックスを取得する必要があります。理由は、それ以外の場合、wait()を呼び出す別のスレッドと並行している場合、wait()またはsignal()が勝つかどうかに応じて完全に異なる動作を得るためです: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に類似しています。
他のヒント
Butenhofの優れた「POSIXスレッドを使用したプログラミング」この権利については、3.3.3章の最後で説明します。
基本的に、mutexをロックせずにcondvarにシグナルを送ることは、潜在的なパフォーマンスの最適化です。シグナルスレッドにmutexがロックされている場合、condvarでウェイクするスレッドは、すぐにmutexをブロックする必要がありますシグナルスレッドが待機スレッドが使用するデータを変更していない場合でも、シグナルスレッドはロックされています。
「予測できないスケジューラの動作」が発生する理由condvarで待機している高優先度のスレッド(別のスレッドが高優先度のスレッドに信号を送り、ウェイクアップする)がある場合、他の低優先度のスレッドが来てmutexをロックし、condvarがシグナルが送信され、高優先度のスレッドが起動されると、低優先度のスレッドがミューテックスを解放するまで待機する必要があります。シグナリング中にミューテックスがロックされている場合、優先順位の高いスレッドは、優先順位の低いスレッドよりも先にミューテックスでスケジュールされます。スケジューラーが許可するとすぐに起動する高優先度スレッド(もちろん、高優先度スレッドにシグナルを送る前にミューテックスを待機する必要があるかもしれませんが、それは別の問題です)。
ミューテックスとペアになった条件変数を待機するポイントは、アトミックに待機に入り、ロックを解除することです。ロックを取得します。あなたが説明することは、パイプ、ソケット、シグナル、またはおそらく最も適切なもののような他の多くの方法で行うことができます-セマフォ。
これは機能するはずです(テストされていないコードに注意してください):
// 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
条件は、可能な限りミューテックスの外部で通知する必要があります。ミューテックスは、並行プログラミングで必要な悪です。それらの使用は、複数のプロセッサの使用から得られる最大パフォーマンスをシステムから奪う競合につながります。
ミューテックスの目的は、プログラム内のいくつかの共有変数へのアクセスを保護して、それらがアトミックに動作するようにすることです。信号操作がミューテックス内で実行されると、共有データの保護とは無関係の数百の無関係なマシンサイクルがミューテックスに含まれます。潜在的に、ユーザー空間からカーネルに至るまで呼び出します。
「予測可能なスケジューラの動作」に関する注意標準では完全に偽物です。
マシンでステートメントを予測可能で明確に定義された順序で実行する場合、そのためのツールは実行の単一スレッド内でのステートメントの順序付けです: S1; S2
。ステートメント S1
は「スケジュール済み」です。 S2
の前。
一部のアクションが独立しており、それらのスケジューリング順序が重要ではないことがわかったときにスレッドを使用します。リアルタイムイベントへのタイムリーな応答や複数のプロセッサでの計算など、パフォーマンス上のメリットを実現する必要があります。
スケジューリングの順序が複数のスレッド間で重要になる場合、これは priority と呼ばれる概念に該当します。優先順位は、N個のステートメントのいずれかが実行される可能性がある場合に最初に起こることを解決します。マルチスレッドで注文するための別のツールは、キューイングです。イベントは1つ以上のスレッドによってキューに入れられ、単一のサービススレッドがキューの順序でイベントを処理します。
要点は、 pthread_cond_broadcast
の配置は、実行順序を制御するための適切なツールではないということです。プログラムが突然すべてのプラットフォームでまったく同じ、再現可能な動作をするという意味で、実行順序を予測可能にしません。
"予測不可能なスケジューリング動作"それだけを意味します。何が起こるかわかりません。 実装も行いません。期待どおりに動作する可能性があります。アプリがクラッシュする可能性があります。それは何年も正常に動作する可能性があり、その後、競合状態によりアプリが猿になります。デッドロックする可能性があります。
基本的に、ドキュメントで指示されていることを実行しない限り、未定義/予測不能な何かをドキュメントが示唆している場合は、それを実行することをお勧めします。他の物はあなたの顔で爆発するかもしれません。 (そして、コードを実稼働に移すまで、それは爆発しません。ただあなたをさらにいらいらさせます。少なくともそれは私の経験です)