// mutex and scondition variable for the problem
mutable boost::mutex conditionMutex;
mutable boost::condition_variable condition;
inline void doTheThing() const {
if (noone doing the thing) {
try {
doIt()
// I succeeded
failed = false;
condition.notify_all();
}
catch (...) {
// I failed to do it
failed = true;
condition.notify_all();
throw
}
else {
boost::mutex::scoped_lock lock(conditionMutex);
condition.wait(lock);
if (failed) {
// throw the same exception that was thrown from
// thread doing notify_all
}
}
は}だから、doTheThing()
を打つ最初のスレッドがdoIt()
を呼びたい、とdoTheThing()
を打つすべての後続のスレッドは、彼らが進む前にdoIt()
を呼び出して終了する最初のスレッドを待ちます。
私は、これはトリックやるべきだと思う:
boost::mutex conditionMutex; // mutable qualifier not needed
bool failed = false;
bool done = false;
inline void doTheThing() const {
boost::unique_lock uql(conditionMutex);
if (!done) {
done = true;
try {
doIt();
failed = false;
}
catch (...) {
failed = true;
throw
}
}
else if (failed)
{
uql.unlock();
// now this thread knows that another thread called doIt() and an exception
// was thrown in that thread.
}
}
重要事項:
doTheThing()
がロックを取る必要があります呼び出すすべてのスレッドを。これを回避する方法はありません。あなたはスレッドを同期させており、スレッドは別のスレッドで何が起きているかを知るために、ロックを取らなければなりません。 (または原子メモリ操作を使用することもできますが、それはより高度な技術です)。failed
とdone
という変数はconditionMutex
によって保護されています。
例外をスローすることによって、関数が通常またはを終了すると、C++はデストラクタをuql
として呼び出します。
EDITああ、他のすべてのスレッドに例外を投げるのは、それを忘れて、ほとんど不可能で、C++でのやり方ではありません。代わりに、各スレッドは、先に示したところで最初のスレッドがdoIt()
を正常に呼び出すかどうかを確認できます。
EDIT例外を別のスレッドに伝播するための言語サポートはありません。 の伝搬例外を別のスレッド〜に渡すと、メッセージは別のスレッドに渡されます。スレッド(boost::asio::io_service::post())間でメッセージを渡す問題に対するライブラリソリューションはたくさんあります。例外を含むメッセージを渡し、メッセージの受信時にその例外をスローする方法があります。しかし、それは悪い考えです。エラーが発生した場合にのみ例外をスローして、通常の関数呼び出しでコールスタックを解くことを防ぎます。それは例外です。普通の方法を返すときに関数から戻る別の方法は意味をなさない。
お返事ありがとうございます。私はif文をロックして、他の人に渡す必要があることを知っています。私はちょうど擬似コードからのロックアウトを残しました。あなたのソリューションは、すべてのスレッドがdoIt()を通過する必要があるという要件を持っています。私は、ブロックされたスレッドが、何をしているのかを作業スレッドが終了するのを待つようにします。実際の問題は、同期スレッドに可能性のある例外をどのように伝播するかにありました。あなたはこれが全く不可能だと言っていますか? – Lauri
@Lauri 1 of 2:注意深く見てください。最初のスレッドだけが 'doIt()'を通過し、残りのスレッドは 'done'をチェックした後に' doIt() 'をスキップします。 –
@Lauri 2 of 2:私は私の答えを明らかにしました、上記を参照してください。 –