C++98/C++11 スレッド 入門

## まえふり
初めて仕事でC++を書くことがあって、特殊なことにC++98とC++11の環境がありました。
双方でどういう風にスレッド処理が実現できるのか分かったのでメモとなります。

環境はMacでしたがC++のコマンドはLinuxベースなのでUbuntuでも同じコマンドじゃないかなと思います。
Winの場合は、Visual StudioでC++開発ができるようなので、そちらで実行してみてくださいm(_ _)m

## やったこと
もちろん仕事内容は書けないのでサンプルを使ってまとめます。
例えば、メインスレッド(もしくはUIスレッドなど)で処理が一切止まらないように裏側で別の処理を走らせてその結果を定期的にメインスレッドへ更新させるサブスレッドを作りたいケースが出てくると思います。
<img src="https://qiita-image-store.s3.amazonaws.com/0/82601/942edc58-3a8c-e2d4-915b-0b622965453e.png" width=38.35%>
※Galaxy Note 8でささっと書いたので絵の上手い下手はご了承ください＞＜

さて、これをC++で実装するにはどうしたら良いのか。
調べるとC++のバージョンによってサポートしているライブラリが異なり、C++98だと**pthread**、C++11だと**std::thread**を使うことになると分かりました。
参考の記事は最後にまとめるので、まずは話しを進めていきます💪✨

### サンプルについて
分かりやすいように**サブスレッドでは単純な計算をする処理**を実行させ、その**計算結果を表示させる処理をメインスレッド**で実装しました。
Webやスマホのアプリ開発でもMVC/MVVMのモデルパターンで開発していくとほぼ同じような設計になると思うのでイメージしやすいのではないでしょうか。

### C++98
```cpp
/*
 * PthreadSample.cpp
 */
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void subMethod(void* pArg)
{
    printf("subMethod start \n");
    int *pVal = (int*) pArg;
    for(int i = 0; i < 3; i++)
    {
        sleep(1);
        *pVal *= 2;
    }
    printf("subMethod end \n");
}

void *subThread(void* pArg)
{
    printf("subThread start \n");
    int *pVal = (int*) pArg;
    *pVal = 200;
    sleep(3);

    subMethod(pVal);

    printf("subThread end \n");

    return 0;
}

int main()
{
    pthread_t handle;
    int data = 100;
    printf("main init [%d]\n", data);

    pthread_create(&handle, NULL, subThread, &data);

    for(int i = 0; i < 10; i++)
    {
        sleep(1);
        printf("main now [%d]\n", data);
    }

    pthread_join(handle, NULL);

    return 0;
}
```

```shell
> clang++ ./PthreadSample.cpp -g -o ./PthreadSample.run
> ./PthreadSample.run
main init [100]
subThread start
main now [200]
main now [200]
subMethod start
main now [200]
main now [400]
main now [800]
subMethod end
subThread end
main now [1600]
main now [1600]
main now [1600]
main now [1600]
main now [1600]
```

### C++11
```cpp
/*
 * ThreadSample.cpp
 */
void subMethod(int *pVal)
{
    printf("subMethod start \n");
    for(int i = 0; i < 3; i++)
    {
        sleep(1);
        *pVal *= 2;
    }
    printf("subMethod end \n");
}

void subThread(int *pVal)
{
    printf("subThread start \n");
    *pVal = 200;
    sleep(3);

    subMethod(pVal);

    printf("subThread end \n");
}

int main() {
    using namespace std;
    int data = 100;
    printf("main init [%d]\n", data);

    thread handle(subThread, &data);

    for(int i = 0; i < 10; i++)
    {
        sleep(1);
        printf("main now [%d]\n", data);
    }

    handle.join();
    handle.detach();

    return 0;
}
```

```shell
> clang++ -std=c++11 -stdlib=libc++ -Weverything ./ThreadSample.cpp -g -o ./ThreadSample.run
> ./ThreadSample.run
main init [100]
subThread start
main now [200]
main now [200]
subMethod start
main now [200]
main now [400]
main now [800]
subMethod end
subThread end
main now [1600]
main now [1600]
main now [1600]
main now [1600]
main now [1600]
```


## まとめ
動かしてみると分かりますが、上記の実行結果とはたまに異なることがあります。
それは、サブスレッドにしたことで処理の同期をしていないこととその時のCPU処理によって状況が変わるからです。

動きは同じ感じですが実装面だと`pthread`に指定するメソッドは`static`でないと指定できません。
上記の場合、`static`ではありませんが、ヘッダークラス`.h`でメソッドを定義した際に`static`指定にし、`.cpp`側では上記のように`static`指定無しでも大丈夫なようです。

ここで重要なのは、**引数で渡すメインスレッドとサブスレッドで扱う変数をポインタで渡している**のですが、この取り扱いには十分注意が必要です。
時に何かの処理で値を代入した際に`NULL`が入ってしまいエラーでアプリが止まってしまうケースが出てくると思います。
必ず例外処理や同じ資源を扱う際の管理方法もちゃんと決めて実装することです。

### 参考記事
- [C++ マルチスレッドプログラミング](https://www.slideshare.net/hotwatermorning/c-38563753)
- [スレッドセーフという幻想と現実](https://yohhoy.hatenablog.jp/entry/2013/12/15/204116)
- [C++11で始めるマルチスレッドプログラミングその1 ～std::thread事始め～](https://suikaba.hatenablog.com/entry/2014/08/19/225703)
- [まくまくC/C  ノート： pthread でスレッドを生成する ](https://maku77.github.io/cpp/pthread/create-thread.html)
- [How to compile C++ with C++11 support in Mac Terminal](https://stackoverflow.com/questions/14228856/how-to-compile-c-with-c11-support-in-mac-terminal)