如何在c ++ 11中多线程读取文件?

时间:2015-03-13 08:51:35

标签: c++ multithreading c++11 mutex

我有一个大文件,我必须通过块读取它。每次当我读取一个块时,我都要做一些耗时的操作,所以我认为多线程读取可能有所帮助,每个线程逐个读取一个块并进行操作。这是我在c ++ 11中的代码

#include<iostream>
#include<fstream>
#include <condition_variable>
#include <mutex>
#include <thread>
using namespace std;
const int CHAR_PER_FILE = 1e8;
const int NUM_THREAD = 2;
int order = -1;
bool is_reading = false;
mutex mtx;
condition_variable file_not_reading;
void partition(ifstream& is)
{
    while (is.peek() != EOF)
    {
        unique_lock<mutex> lock(mtx);
        while (is_reading)
            file_not_reading.wait(lock);

        is_reading = true;
        char *c = new char[CHAR_PER_FILE];

        is.read(c, CHAR_PER_FILE);
        order++;

        is_reading = false;

        file_not_reading.notify_all();
        lock.unlock();

        char oc[3];
        sprintf(oc, "%d", order);
        this_thread::sleep_for(chrono::milliseconds(2000));//some operations that take long time
        ofstream os(oc, ios::binary);
        os.write(c, CHAR_PER_FILE);
        delete[] c;
        os.close();
    }
}

int main()
{
    ifstream is("bigfile.txt",ios::binary);
    thread threads[NUM_THREAD];
    for (int i = 0; i < NUM_THREAD; i++)
        threads[i] = thread(partition, ref(is));

    for (int i = 0; i < NUM_THREAD; i++)
        threads[i].join();

    is.close();
    system("pause");
    return 0;
}

但是我的代码没有用,它只创建了4个文件而不是`bigfilesize / CHAR_PER_FILE,并且线程似乎卡住了,我怎么能让它工作?

是否有任何c ++ 11多线程读取文件实现或示例?

感谢。

4 个答案:

答案 0 :(得分:5)

我的建议:

  • 使用一个线程从文件中读取块。每次读取一个块时,将其发布到请求队列。不值得阅读多线程,因为会有内部锁定/阻塞读取公共资源。
  • 使用线程池。他们每个人都从队列中读取,检索一个块,执行昂贵的操作并返回等待新的请求。
  • 队列必须受互斥保护。
  • 不要使用比你拥有的处理单元数(CPU /内核/超线程数)更多的线程。
  • 上述主要警告是它不保证处理顺序。您可能需要将结果发布到可以重新排序的中心位置(再次显示中心位置 - &gt;必须受互斥保护)。

答案 1 :(得分:1)

您可以将基于任务的并行性与std :: async:

结合使用
class result; // result of expensive operation
result expensive_operation(std::vector<char> const& data)
{
 result r = // long computation
 return r;
}

std::vector<char>::size_type BLOCK_SIZE = 4096;

std::vector<std::future<result>> partition(ifstream& in)
{
    std::vector<std::future<result>> tasks;

    while (!in.eof() && !in.fail())
    {
        std::vector<char> c(BLOCK_SIZE);
        is.read(c.data(), BLOCK_SIZE);
        c.resize(in.gcount());
        tasks.push_back( std::async( [](std::vector<char> data) 
        {
            return expensive_operation(data);
        },
        std::move(c) ));
    }
    return tasks;
}

int main()
{
    ifstream is("bigfile.txt",ios::binary);
    auto results = partition(is);

    // iterate over results and do something with it
}

答案 2 :(得分:0)

是否必须以“顺序”顺​​序读取文件,即必须按特殊顺序“操作”块?否则你可以例如制作4个线程,让每个线程读取文件的1/4(你可以通过使用tellg并在例如向量或变量中保存位置来实现)。这样你就不必使用锁。

也许您可以告诉我们您所阅读的数据是如何评估的。

答案 3 :(得分:0)

...也许

void partition(ifstream& is)
{
    unique_lock<mutex> lock(mtx);
    std::vector<char> c(CHAR_PER_FILE);
    is.read(c.data(), CHAR_PER_FILE);
    lock.unlock();

    if (is.fail() && !is.eof()) return;
    size_t num_bytes_read = is.gcount();

    std::ostringstream oc;
    oc << order;
    this_thread::sleep_for(chrono::milliseconds(2000)); //take long time
    if (std::ofstream os(oc, ios::binary))
        os.write(c.data(), CHAR_PER_FILE);
}

注意:

  • 互斥锁已将操作序列化 - 不需要条件变量。

  • 我添加了一点输入错误和字节读取处理 - 您应该在os.write()之后检查,为失败的else创建添加ofstream等。