std::vector を mutex でロックしてマルチスレッドで書き込む
C++ の std::thread でひとつの vector に push_back しまくるコード
#include <iostream> #include <vector> #include <thread> int main() { std::vector<int> vi; std::vector<std::thread> vt; for(int i=0; i<100; ++i) { vt.push_back(std::thread([&i, &vi]{ vi.push_back(i); })); } for(int i=0; i<100; ++i) { vt[i].join(); } return 0; }
これをコンパイルして実行すると
$ g++ test.cpp -pthread $ ./a.out (...) Aborted (core dumped)
当然こうなる。 というわけで mutex を使って vector をロックするようにする。正確には、vector をメンバとして持ち、ロックもできる class をつくる。
#include <iostream> #include <vector> #include <thread> #include <mutex> class myvector { std::mutex mtx; std::vector<int> data; public: void push_back(int x) { std::lock_guard<std::mutex> lock(mtx); data.push_back(x); } void print() { for(int x: data) { std::cout << x << '\n'; } } }; int main() { const int N = 100; std::vector<std::thread> vt; myvector mv; for(int i=0; i<N; i++) { vt.push_back(std::thread([=, &mv]{ mv.push_back(i); })); } for(int i=0; i<N; i++) { vt[i].join(); } mv.print(); }
これで 0 〜 99 までの数字が出力される。順番が正確に 0 〜 99 ではないのは並列化のため。
なお最初ラムダ式のところをうっかり
vt.push_back(std::thread([&i, &mv]{ mv.push_back(i); }));
と書いていたが、これだと i がコピーではなく参照になってしまうので、 mv に入る i の値が正確に 0〜99 でなくなってしまった(たいてい 2 から始まる)。ラムダ式に対し意味もわからず「使う変数を & で書いとくんやろ」という甘い考えを持っていたことを反省。