2つ以上のスレッド間で共有メモリをC/C ++でJavaのように待機して通知するには、pthreadライブラリを使用します。
6 に答える
待機/通知に使用するJavaオブジェクトの代わりに、ミューテックスと条件変数の2つのオブジェクトが必要です。これらはとで初期化されpthread_mutex_init
ますpthread_cond_init
。
Javaオブジェクトで同期する場合は、とを使用pthread_mutex_lock
しますpthread_mutex_unlock
(Cでは、これらを手動でペアリングする必要があることに注意してください)。待機/通知する必要がない場合は、ロック/ロック解除するだけで、条件変数は必要ありません。ミューテックスだけが必要です。ミューテックスは必ずしも「再帰的」ではないことに注意してください。これは、すでにロックを保持している場合、その動作が必要であることを示すinitフラグを設定しない限り、再度ロックを取得できないことを意味します。
電話をかけた場所java.lang.Object.wait
、電話pthread_cond_wait
、またはpthread_cond_timedwait
。
あなたが呼んだであろう場所java.lang.Object.notify
で、を呼んでpthread_cond_signal
ください。
あなたが呼んだであろう場所java.lang.Object.notifyAll
で、を呼んでpthread_cond_broadcast
ください。
Javaの場合と同様に、待機関数から誤ったウェイクアップが発生する可能性があるため、シグナルの呼び出しの前に設定され、待機の呼び出しの後にチェックされる条件が必要ですpthread_cond_wait
。また、ループで呼び出す必要があります。Javaの場合と同様に、待機中にミューテックスが解放されます。
notify
モニターを持たないと電話をかけられないJavaとは異なり、実際にはミューテックスを持たずに電話をかけることができます。pthread_cond_signal
ただし、通常は何も得られず、多くの場合、非常に悪い考えです(通常、ロック-条件の設定-シグナル-ロック解除が必要なため)。したがって、それを無視してJavaのように扱うのが最善です。
それ以上のものはありません。基本的なパターンはJavaと同じであり、偶然ではありません。ただし、知りたい、または避けたいさまざまなフラグやおかしな動作があるため、これらすべての機能のドキュメントを読んでください。
C ++では、pthreadsAPIを使用するよりも少しうまくいくことができます。少なくともRAIIをミューテックスのロック/ロック解除に適用する必要がありますが、使用できるC ++ライブラリによっては、pthread関数にもっとC++風のラッパーを使用した方がよい場合があります。
タイトルでは、CとC++をさりげなくブレンドして「C/C++」にします。私はあなたが2つの混合物であるプログラムを書いているのではないことを願っています。
C ++ 11を使用している場合は、移植性があり(C ++であるため)、pthreadの代わりにはるかに安全で使いやすいものが見つかります(POSIXシステムでは、通常、内部でpthreadを使用します)。
待機/通知にはstd::condition_variable
+を使用できます。この例は、次の方法を示しています。std::mutex
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool mainReady = false;
bool workerReader = false;
void worker_thread()
{
// Wait until main() sends data
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return mainReady;});
}
std::cout << "Worker thread is processing data: " << data << std::endl;
data += " after processing";
// Send data back to main()
{
std::lock_guard<std::mutex> lk(m);
workerReady = true;
std::cout << "Worker thread signals data processing completed\n";
}
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
mainReady = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return workerReady;});
}
std::cout << "Back in main(), data = " << data << '\n';
// wait until worker dies finishes execution
worker.join();
}
このコードは、C++がCよりも優れている他のいくつかの長所も強調しています。
- このコードには、(危険な)生のポインターが1つ含まれていません
- ラムダ式
- 他のすべての種類の構文スワッグ。
pthread_cond_waitとpthread_cond_signalを使用して、条件に基づいて同期することができます
条件変数の使用はそれを行う1つの方法です。Linuxでライブラリを使用するときに条件変数を使用できますpthread
(リンクを参照)。
条件変数は、タイプpthread_cond_tの変数であり、待機およびその後のプロセス継続のための適切な関数とともに使用されます。
移植性を気にしない場合、Linuxはeventfdを提供します。これは、まさにあなたが望むものを提供します。各eventfdは内部カウンターを保持します。デフォルトモードでは、カウンタがゼロの場合はeventfdブロックからの読み取り、それ以外の場合はすぐに戻ります。それに書き込むと、内部カウンターに追加されます。
したがって、待機呼び出しは単なる、uint64_t buf_a; read(event_fd, &buf_a, sizeof(buf_a));
であり、bufは8バイトのバッファである必要があります。待機中のスレッドに通知するには、次のようにしますuint64_t buf_b = 1; write(event_fd, &buf_b, sizeof(buf_b));
。
可能な場合は、POSIXセマフォを使用できます。pthreadライブラリにはミューテックスがあり、これも機能する可能性があります。