C++で簡単非同期処理(std::thread,std::async)

C++11では`<future>`ヘッダが導入され、
簡単に非同期の処理が実装できるようになった。
以下では用途毎に実装方法をまとめる。
thread間での同期の話はせず、あくまで完全に非同期な処理についてまとめる。

## 戻り値が必要ない場合(Thread-per-message pattern)
とりあえず非同期に実行できればいい場合。
実行時間を短縮するために複数の独立な処理を並列に実行するなどの応用が考えられる。
`std::thread`を使用する。最も基本的な使い方は以下の通りである：

```cpp
auto th1 = std::thread([]{ do_long_work(); });
do_another_things();
th1.join();
```

`std::thread`の引数に実行したい関数を渡す。
関数に引数を与えたい場合は、`std::thread(func, arg)`のように行う。
プログラムが終了するまでには`join()`しないといけない。
`std::thread`の引数のlambda式はキャプチャする事もできる:

```cpp
double a;
auto th1 = std::thread([&a]{ a = long_calc(); });
do_another_things();
th1.join();
std::cout << a << std::endl; // 1.0
```

`std::vector<std::thread>`のようにコンテナに入れる事もできる。

```cpp
#include <vector>
#include <future>
#include <iostream>

int main(int argc, char const *argv[]) {
  std::vector<int> v(10);
  std::vector<std::thread> threads;
  for (int i = 0; i < 10; ++i) {
    threads.push_back(std::thread([i, &v] { v[i] = i * i; }));
  }
  for (std::thread &th : threads) {
    th.join();
  }
  for (int i : v) {
    std::cout << i << std::endl;
  }
  return 0;
}
```

*参考文献*
- [std::thread - cppreference](http://en.cppreference.com/w/cpp/thread/thread)
- [std::threadをあとから開始。それとムーブ対応したコンテナについて](http://faithandbrave.hateblo.jp/entry/20120418/1334731512) (vectorに入れる部分)

### コンパイル時の注意
コンパイルする際は並列用のライブラリをリンクする事を忘れずに。
例えばLinuxではpthreadをリンクする。

```console
$ g++ -std=c++11 source.cpp -pthread
```

```console
$ clang++ -std=c++11 source.cpp -pthread
```

リンク忘れると実行時にエラーになる：

```console
terminate called after throwing an instance of 'std::system_error'
  what():  Enable multithreading to use std::thread: Operation not permitted
```

## 結果を取得したい場合
上述の方法でも戻り値を参照でキャプチャした変数に代入する事ができているが、
これでは不便な場合も多い。
そこで登場するのが`std::async`である。

```cpp
auto result = std::async(std::launch::async, [] { return long_calc(); });
do_another_things();
std::cout << result.get() << std::endl;
```

`result`の型は`std::future<T>`(`T`は`long_calc()`の戻り値の型)である。
`result.get()`ではじめて作成したスレッドを`join()`するので、
`do_another_things()`はthreadの生成直後に(`long_calc()`の実行を待たずに)実行される。

### 非同期処理をどうやって実行するか(Policy)
第一引数の`std::launch::async`はpolicyを指定しており、
別スレッドを開始して`long_calc()`を計算する、という指定である。
Policyは次の4通りの指定ができる

- `std::launch::async` : 別スレッドで実行 
- `std::launch::deferred` : 遅延評価
- `std::launch::async | std::launch::deferred` : 上記のいずれか（実装依存）
- 指定なし : 両方指定した場合と同様

`std::launch::deferred`を指定した場合は単に遅延評価になる。
つまり最初に`result.get()`が呼ばれたタイミングで`long_calc()`を評価する。
次回以降に`result.get()`が呼ばれたら最初の時に計算した値を返す。

`std::async(std::launch::async | std::launch::deferred, func, arg)`のように両方指定する場合、
あるいは単に`std::async(func, arg)`のように省略した場合は、
async/deferredのどちらになるか実装依存である。

vectorを初期化する場合は以下のようにする:

```cpp
#include <future>
#include <iostream>
#include <vector>

int main(int argc, char const *argv[]) {
  std::vector<std::future<int> > v;
  for (int i = 0; i < 10; ++i) {
    v.push_back(std::async([i] { return i * i; }));
  }
  for (auto &val : v) {
    std::cout << val.get() << std::endl;
  }
}
```

*参考文献*
- [std::async - cppreference](http://en.cppreference.com/w/cpp/thread/async)
- [std::future - cppreference](http://en.cppreference.com/w/cpp/thread/future)
- [C++/CXの旅(9)：C++11の標準タスク処理のまとめ(std::future/promise/thread/async)](http://blog.livedoor.jp/haruka_sao/archives/52047261.html)
- [GNU/LinuxのC++11でプログラミングの常識がひっくりかえった](http://cpplover.blogspot.jp/2013/04/gnulinuxc11.html)(非同期の例外について詳しい)

## Thread Pool (Worker Thread) pattern
C++でスレッドプール(ワーカースレッド)パターンを実装する方法は方々で議論されている。

*参考文献*

- C++11で実装する場合
    - [A Thread Pool with C++11](http://progsch.net/wordpress/?p=81)
    - [progschj/ThreadPool - GitHub](https://github.com/progschj/ThreadPool)
- Boost.Asioを使用する場合
    - [Boost.Asioによるワーカースレッドパターン](http://faithandbrave.hateblo.jp/entry/20110408/1302248501)

次回に詳しくまとめる。