parallel_do で遊んでたんだけども。
parallell_for の汎用版とでも言ったらいいのか、これめっちゃおもろいわ。
parallel_do(first, last, job) すると、[first,last) の範囲にある iter に対し、
job(*iter) を呼んでくれる(しかも複数のジョブを同時並行で)わけだが、
job(*iter) の中でお仕事を追加できるのよ。
これ使うと再帰的な処理を非再帰なジョブに置き換えられる。
たとえば、与えられたディレクトリ内のファイルを列挙するとしよう。
ディレクトリ内にディレクトリがあったら、さらにそのディレクトリ内を
ほじくりたいので、ふつーに書くと再帰となる。
void 列挙(フォルダ) {
foreach ( ファイル item in フォルダ内のファイル ) {
if ( item がフォルダだったら ) {
列挙(item); // ここで再帰
} else {
itemのファイル名を出力
}
}
}
みたいなね。これを TBBのparallel_do でやってみた。
/*
* コマンドラインで与えられたディレクトリにある
* ファイル名を再帰的に列挙する。
* マルチスレッドなんで列挙順がぐちょぐちょ。
* どんなに順番狂ってても
* ORDEREDを定義しとけばなおるよ。
ハ_ハ
('(゚∀゚∩ なおるよ!
ヽ 〈
ヽヽ_)
*/
#include <windows.h> // FindFirstFile/FindNextFile/FindClose
#include <iostream> // cout, endl
#include <string> // string
#include <vector> // vector
#ifdef ORDERED
#include <queue> // priority_queue
#include <functional> // greater
#endif
#include <tbb/tbb.h> // mutex, parallel_do
using namespace std;
class finder {
static tbb::mutex mutex;
public:
#ifdef ORDERED
static priority_queue<string,vector<string>,greater<string> > result;
#endif
// お仕事: 与えられた dir 内のファイル名を列挙する
void operator()(string dir, tbb::parallel_do_feeder<string>& feeder) const {
WIN32_FIND_DATA data;
HANDLE handle = FindFirstFile((dir+"/*.*").c_str(), &data);
if ( handle != INVALID_HANDLE_VALUE ) {
do {
string name = data.cFileName;
string path = dir + "/" + name;
// 見つけたエントリがディレクトリであったならお仕事追加
if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
if ( name != "." && name != ".." ) {
feeder.add(path); // すごくね!?
}
} // ファイルであったなら列挙
else {
tbb::mutex::scoped_lock lock(mutex);
#ifdef ORDERED
result.push(path);
#else
cout << path << endl;
#endif
}
} while ( FindNextFile(handle, &data) );
FindClose(handle);
}
}
};
tbb::mutex finder::mutex;
#ifdef ORDERED
priority_queue<string,vector<string>,greater<string> > finder::result;
#endif
int main(int argc, char* argv[]) {
if ( argc < 2 ) return -1;
vector<string> dirs(argv+1,argv+argc);
// お仕事開始!
tbb::parallel_do(dirs.begin(), dirs.end(), finder());
#ifdef ORDERED
while ( !finder::result.empty() ) {
cout << finder::result.top() << endl;
finder::result.pop();
}
#endif
}
いやー、TBBおもろい。ドキドキがいっぱい♪