30839


マルチスレッドとは、簡単に言えばプログラムを処理するものを増やすことです。しかし、そのマルチスレッドが危険と聞いたことがあります。

マルチスレッドが何故危険なのでしょうか。


CC BY-SA 3.0
2016-12-02T09:37:51.657
30837
2016-12-03T05:30:17.070
15185
question
マルチスレッド
マルチスレッドはなぜ危険ですか？


危険というのは、正しく理解して使わないと、計算結果が間違ったり予期しないエラーが発生する事があるという事を注意喚起だと思います。

ここに数字を＋１ する 関数 add() と 数字を -1 する sub() 関数があるとします。

順番に add() を 100回 実行し sub() を 100回 実行すると 元の数字に戻りますが

マルチスレッドで add() 100回 と sub() 100回を マルチスレッドで並列して動作させると  
違う値になる可能性があります。

[code]

    int i = 5;
    
    void add() {
     i = i + 1;
    }
    void sub() {
     i = i - 1;
    }
    
[/code]

こんな なんでもない処理でも、マルチスレッドでは動作させることができないのです。

危険だと思いませんか？

だからある程度プログラムがちゃんとできるようになるまでは、マルチスレッドは  
避けておいた方が良いですよ・・と親切心から「危険」と言っているのだと思います。


CC BY-SA 3.0
2016-12-02T10:35:02.643
30839
2016-12-02T10:35:02.643
18851
30837
answer


MultiThread is evil
みたいな英語文章を見たことがあります。端的に言うと、正しいプログラミングが恐ろしく難しくって(あるメモリ上の値が複数スレッドから読み書きされた場合の挙動とか、とても難解で何度読んでも忘れます)、かつ、原因不明のバグの温床に、とても簡単になってしまうし、デバッグも極めて困難だ、みたいな文章だったような気がしてます。

まず、マルチスレッドではなくて、マルチプロセスで対応できるなら基本的にそっちで行なう方が大体正しい設計だと思います。どうしてもマルチスレッドしたいのでしたら、ライブラリを注意深く使いましょう。自前で
mutex
とかそれより下のレイヤーを触り出したら、それは多分マルチスレッドライブラリを書くのと同じぐらいの注意を割くことに、結果的になると考えていて、それが本当にやりたいことでないかぎり、やるべきではないのではないかと思っています。


CC BY-SA 3.0
2016-12-02T16:24:39.510
30848
2016-12-02T16:24:39.510
754
30837
answer


マルチコアCPUが当たり前になって居ることも有り、今時マルチスレッドにする事は珍しくありません。危険とまで表現するのはオーバーと思います。もちろんマルチスレッドにする上で気をつけるべき事はあります。

アトミックではない操作は、途中で別スレッドが実行される可能性が常にあります。  
k systemさんも書かれているので割愛しますね。

ループアンローリングによって他スレッドで変更した値が反映されなくなる事があります。

[code]

    int a = 0;
    void thread1()
    {
        a = 1;
    }
    void thread2()
    {
        while(a==0)
        {
            …
        }
    }
    
[/code]

このような記述をした場合、コンパイラの最適化によりa==0の判定結果はループ内で変化しないと見なしてループの外側で処理されるようになります。

アウトオブオーダー実行は同一コア上で結果に違いが発生しないように命令を置き換えますが、別コアとの相互作用までは考慮しません。

[code]

    int a = 0;
    int b = 0;
    int c = 0;
    void thread1()
    {
        a = 3;
        b = 2;
        c = 1;
    }
    void thread2()
    {
        while(c==0){};
        int d = a + b;
    }
    
[/code]

aとbに値を設定した後でcのフラグを1にしているつもりでもCPUがその順番通りに処理する保証はありません。c =
1が先に実行された結果、dには0、2、3の何れかが格納される可能性があります。

ライブラリの中にはスレッド毎に初期化処理が必要なものもあります。適切な方法でスレッドを起動するなり、スレッドの起動後に初期化処理を行うなり、適切な手順を守らなくてはなりません。環境に強く依存する話なので、例示は出来ませんが。

これらを考慮に入れた上で、スピンロックなり、クリティカルセクションなり、ミューテックスなりの同期命令を使って排他制御を行うことになります。


CC BY-SA 3.0
2016-12-03T05:30:17.070
30860
2016-12-03T05:30:17.070
12774
30837
answer