TBB之pipeline

Pipelining是一个通用并行模型,模仿一个传统的制造集成生成线,数据流向一系列的管道滤波,每个滤波以某种方式处理数据,给定一个输入流数据,一些滤波能并行操作,另外一些不能。例如,视频处理,对帧的处理不依赖其他帧,那么能同时处理多个帧,反之,对帧的操作需要首先处理先前的帧。

TBB类pipeline和filter实现pipeline模式。一个简单的文本处理例子会被使用证明pipeline和filter的用法。这个例子读取一个文本文件,平方这个文本里的每个数,写出改变的文本到一个新的文件里,流程如下:
这里写图片描述

这个滤波作用是提取文本中一行的数据:

class InputStream: public filter {
public:
    explicit InputStream(ifstream* file):m_file(file), filter(serial_in_order) {} // filter初始化serial_in_order(串行)
    ~InputStream() {}

    void* operator()(void*) {
        ostringstream out;
        vector<string> vec_str;
        string str;

        if(!getline(*m_file, str)) {
            return NULL;
        }
        _split(str, ' ', vec_str);
        // 把开辟内存,准备存放固定格式的数据
        int length = vec_str.size();
        char* result = new char[length*sizeof(int) + sizeof(int)];
        vector<string>::iterator _it = vec_str.begin();
        // 把数据转成整形,存成固定格式
        for (int i = 0; _it != vec_str.end(); ++_it, i++) {
            int temp = atoi((*_it).c_str());
            memcpy(result + sizeof(int) + i*sizeof(int), &temp, sizeof(int));
        }
        memcpy(result, &length, sizeof(int));

        return result;
    }

private:
    ifstream* m_file;
};

这个滤波为对获取的数据进行平方操作:

class Transform: public filter {
public:
    Transform():filter(parallel) {} // filter初始化parallel(并行)
    ~Transform() {}

    void* operator()(void* in_str) {
        if (!in_str) {
            return NULL;
        }

        // 获取数据长度,得到数据的首地址result
        char* char_str = reinterpret_cast<char*>(in_str);
        ostringstream out;
        int* length = reinterpret_cast<int*>(char_str);
        char* result = new char[(*length)*sizeof(int) + sizeof(int)];
        // 遍历获取数据,并对数据进行平方
        for (int i = 0; i < *length; i++) {
            char* temp = (char_str + sizeof(int) + i*sizeof(int));
            int temp_int =  (*(reinterpret_cast<int*>(temp)))*2;
            // 把数据存成固定格式,准备传出去
            memcpy(result + sizeof(int) + i*sizeof(int), &temp_int, sizeof(int));
        }
        memcpy(result, length, sizeof(int));
        return result;
    }
};

这个滤波的作用是输出数据到文件中:

class OutputStream: public filter {
public:
    explicit OutputStream(ofstream* file):m_file(file), filter(serial_in_order) {}

    ~OutputStream() {}

    void* operator()(void* in_str) {
        if (!in_str) {
            return NULL;
        }
        char delim = ' ';
        char cvtline = '\n';
        // 获取数据长度length
        char* char_str = reinterpret_cast<char*>(in_str);
        int* length = reinterpret_cast<int*>(char_str);
        // 把数据存到文件中
        for (int i = 0; i < *length; i++) {
            int* int_str = reinterpret_cast<int*>(char_str + sizeof(int) + i*sizeof(int));
            (*m_file) << *int_str;
            (*m_file) << " ";
        }
        (*m_file) << "\n";
        if (char_str) {
            delete []char_str;
            char_str = NULL;
        }
        return NULL;
    }
private:
    ofstream* m_file;
};

运行管道:

int run_pipeline(int nthreads) {
    string input = "/home/shaomingliang/beh/core/tbb/pipline/input.txt";
    string output = "/home/shaomingliang/beh/core/tbb/pipline/output.txt";
    ifstream in_stream(input.c_str());
    ofstream out_stream(output.c_str());
    if (!in_stream.is_open()) {
        throw invalid_argument(("invalid input file name: " + input).c_str());
    }
    if (!out_stream.is_open()) {
        throw invalid_argument(("invalid output file name: " + output).c_str());
    }

    // 建立管道,加入InputStream滤波
    pipeline pipeline;  
    InputStream input_filter(&in_stream);
    pipeline.add_filter(input_filter);

    // 加入Transform滤波
    Transform trans_filter;
    pipeline.add_filter(trans_filter);

    // 加入OutputStream滤波
    OutputStream out_filter(&out_stream);
    pipeline.add_filter(out_filter);

    // 开始计时并运行pipeline
    tick_count start = tick_count::now();
    pipeline.run(nthreads * 4);
    ostringstream out;
    out << "thread" << nthreads <<" consume time: " << (tick_count::now() - start).seconds() << endl;

    in_stream.close();
    out_stream.close();
    return 1;
}

main函数:

int main(int argc, char** args) {
    try {
        // 获取可利用的线程数
        int p = task_scheduler_init::default_num_threads();
        tick_count global_start = tick_count::now();
        for (int i = 1; i <= p; i++) {
            // 初始化task scheduler并初始化线程数为i
            task_scheduler_init init(i);
            if (!run_pipeline(i)) {
                return 0;
            }
        }
        ostringstream out;
        out << "global consume time: " << (tick_count::now() - global_start).seconds() << endl;
    } catch(exception& e) {
        cerr << "error ocurred. error text is:\"" << e.what() << "\"" << endl;
    }

    return 0;
}

字符串分割函数:

void _split(const string& s, char delim,vector<string>& v) {
    int i = 0;
    size_t pos = s.find(delim);
    while (pos != string::npos) {
      v.push_back(s.substr(i, pos-i));
      i = ++pos;
      pos = s.find(delim, pos);

      if (pos == string::npos)
         v.push_back(s.substr(i, s.length()));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章