書き下記からダウンロードできまException-安全なコード
-
11-07-2019 - |
質問
その間の緊張multithreading、例外-安全にC++?あいガイドラインすか?はスレッドを終了でキャッチされない例外?
解決
C ++標準ではマルチスレッドについて言及されていないと思います-マルチスレッドはプラットフォーム固有の機能です。
C ++標準がキャッチされない例外について一般的に言っていることは正確にはわかりませんが、このページでは、何が起こるかはプラットフォームで定義されています。コンパイラのドキュメントをご覧ください。
g ++ 4.0.1(具体的にはi686-apple-darwin8-g ++-4.0.1を使用)で行った手っ取り早いテストでは、結果は terminate()
が呼び出され、プログラム全体を強制終了します。使用したコードは次のとおりです。
#include <stdio.h>
#include <pthread.h>
void *threadproc(void *x)
{
throw 0;
return NULL;
}
int main(int argc, char **argv)
{
pthread_t t;
pthread_create(&t, NULL, threadproc, NULL);
void *ret;
pthread_join(t, &ret);
printf("ret = 0x%08x\n", ret);
return 0;
}
g ++ threadtest.cc -lpthread -o threadtest
でコンパイルされています。出力は次のとおりです。
terminate called after throwing an instance of 'int'
他のヒント
C ++ 0xには言語がありますスレッド間での例外の転送のサポート:ワーカースレッドが例外をスローしたときに、スポーンスレッドが例外をキャッチまたは再スローできるようにします。
提案から:
namespace std {
typedef unspecified exception_ptr;
exception_ptr current_exception();
void rethrow_exception( exception_ptr p );
template< class E > exception_ptr copy_exception( E e );
}
キャッチされない例外は、 terminate()
を呼び出します。これは、 terminate_handler
(プログラムで設定可能)を呼び出します。デフォルトでは、 terminate_handler
は abort()
を呼び出します。
デフォルトの terminate_handler
をオーバーライドしても、標準では、提供するルーチンは「呼び出し元に戻らずにプログラムの実行を終了する」と規定されています。 (ISO 14882-2003 18.6.1.3)。
したがって、要約すると、キャッチされない例外はスレッドだけでなくプログラムを終了します。
スレッドセーフに関する限り、 Adam Rosenfield が言うように、規格で扱われていないプラットフォーム固有のもの。
これがErlangが存在する最大の理由です。
規約が何であるかはわかりませんが、私見では、可能な限りErlangに似ています。ヒープオブジェクトを不変にし、スレッド間で通信するためのある種のメッセージパッシングプロトコルを設定します。ロックを避けます。メッセージの受け渡しが例外に対して安全であることを確認してください。スタックにできるだけ多くのステートフルなものを保持します。
他の人が議論したように、並行性(特にスレッドセーフ)はアーキテクチャ上の問題であり、システムとアプリケーションの設計方法に影響します。
しかし、例外の安全性とスレッドの安全性との間の緊張について質問したいです。
クラスレベルでは、スレッドセーフにはインターフェイスの変更が必要です。例外安全性と同じように。たとえば、次のようにクラスが内部変数への参照を返すのが慣例です:
class Foo {
public:
void set_value(std::string const & s);
std::string const & value() const;
};
Fooが複数のスレッドで共有されている場合、トラブルが発生します。当然、Fooにアクセスするためにミューテックスまたは他のロックを置くことができます。しかし、すぐに、すべてのC ++プログラマーはFooを&quot; ThreadSafeFoo&quot;にラップしたいと思うでしょう。私の主張は、Fooのインターフェースを次のように変更する必要があるということです。
class Foo {
public:
void set_value(std::string const & s);
std::string value() const;
};
はい、より高価ですが、Foo内のロックを使用してスレッドセーフにすることができます。 IMnsHOこれにより、スレッドの安全性と例外の安全性の間に一定の緊張が生まれます。または、少なくとも、共有リソースとして使用される各クラスを両方の光源の下で検査する必要があるため、より多くの分析を実行する必要があります。
1つの古典的な例(最初に見た場所を覚えていない)は、stdライブラリにあります。
キューから何かをポップする方法は次のとおりです。
T t;
t = q.front(); // may throw
q.pop();
このインターフェースは、以下と比較してやや鈍いです:
T t = q.pop();
しかし、Tコピーの割り当てがスローされる可能性があるため、完了です。ポップが発生した後にコピーがスローされると、その要素はキューから失われ、回復できなくなります。ただし、要素がポップされる前にコピーが行われるため、try / catchブロックのfront()からコピーの周りに任意の処理を配置できます。
欠点は、2つのステップが関係するため、std :: queueのインターフェースでスレッドセーフなキューを実装できないことです。例外の安全性(スローされる可能性のあるステップを分離する)に適しているものは、マルチスレッドには不適切です。
例外の安全性におけるあなたの主な救世主は、ポインター操作がノースローであることです。同様に、ポインター操作はほとんどのプラットフォームでアトミックにできるため、多くの場合、マルチスレッドコードの救世主になります。ケーキを食べて食べることもできますが、本当に大変です。
がん:
g++はLinuxの殺害のスレッド(pthread_cancel)は投げる"不明"には、例外です。一方で、まとめて見ることができる清掃くときにスレッドが殺害されました。一方、場合にキャッチしてください。る例外ではなrethrowで、コードを終了abort().そのため、他の図書館をご利用の殺のスレッドできない
catch(...)
なし
throw;
おねじのコードです。 こちらの はこの動作は
- 時に必要なもの移転の例外とスレッド)。これは簡単にできること-しっsomehackの場合、適切なソリューションには、のような整列化/demarshallingい利用とプロセス。
例外をキャッチせずにおくことはお勧めしません。トップレベルスレッド関数を、プログラムをより適切に(または少なくとも冗長に)シャットダウンできるキャッチオールハンドラでラップします。
最も重要なことは、他のスレッドからのキャッチされない例外がユーザーに表示されないか、メインスレッドでスローされないことを覚えておくことだと思います。したがって、try / catchブロックを使用して、メインスレッドとは異なるスレッドで実行する必要があるすべてのコードをワープする必要があります。