如何使用多个线程读取文件?

时间:2014-11-05 16:47:19

标签: c++ linux multithreading gcc

我为我的操作系统作业解决了以下问题。我做了一些工作,但我还没到那里。非常感谢帮助。

问题

您的任务是创建一个多线程文档分析器。你的程序应该能够使用 处理提供的文件的可变线程数,并生成一些有关它的统计信息。该 所需数字是: • 单词数(通过计算空格数找到) • 字母数量(使用 因而isalpha ()函数) • 标点符号的数量(通过使用。找到) ispunct判断 ()功能)。 下面显示了涉及4个线程的示例运行: $ ./docAnal 4 test.txt 字:1245 信件:24313 标点符号:87 文档应该在所需的线程之间平均分配。你不应该硬编码你的 程序参数。它们应该从命令行中读取,如上例所示

这是我目前的代码

#include <QThread>
#include <iostream>
#include <fstream>
#include <string>
#include <locale>
using namespace std;

//int count=0;
char  buff[200];
class MyThread: public QThread
{
    private : int space, word, punc = 0,countl=0;
    int ID;
public:
    MyThread(int i) : ID(i) {}
    void run (){ ifstream myfile;
        ifstream fin;
        fin.open("example.txt");
        myfile.open("example.txt");
        cout<<"Reading file"<<endl;
        //cout<<"words ="<<word;

        while(!myfile.eof())
        {

            myfile>>buff;
            word++;
            countl=countl+strlen(buff);
        }

        for (int i=0;i<strlen(buff);i++)
        {
            if (ispunct(buff[i])) punc++;
        }

        cout<<"words ="<<word-1<<endl;
        cout<<"Letter="<<countl-(4+punc)<<endl;
        cout<<"Puncuation ="<<punc<<endl;
    }
};

int  main()
{

    MyThread *counter [1];
    for (int i = 0;i<1;i++){
        counter[i] = new MyThread(i);
        counter[i]->start();
    }

    for (int i = 0;i<1;i++){
        counter[i]->wait();
    }
    return 0;
}

我只能使用一个线程获得输出。我不知道如何将其切成部分并使4个线程连续读取它。请指出我正确的方向。

4 个答案:

答案 0 :(得分:2)

您可以获取文件的长度并将该数字除以线程数。

然后,寻找每个潜在的起始位置(使用seekg())并通过读取下一个空格(std::isspace())进行调整,以避免将单词切成两半。

然后将每个开始和结束位置传递给一个线程(结束位置是以下分区的起始位置)。

然后每个线程使用seekg()移动到其指定的位置,tellg()确定它何时到达指定的结束位置。

答案 1 :(得分:0)

我的策略是:

  1. 找出文件中有多少单词,然后将该数字拆分为4

  2. 让每个线程读取文件的1/4。例如,如果文件中有80个单词:

    • 线程1将读取字0-19
    • 线程2将读取字词20-39
    • 主题3将读取单词40-59
    • 主题4将读取单词60-79

答案 2 :(得分:0)

文件是否应该或必须在线程之间平均分配? 如果他们应该这样做,你就可以获得更轻松的工作,获得性能提升并阅读理论上任意大的文件,而无需并行访问文件系统,这将是一个坏主意,因为它会严重影响性能。

如果您只应在线程中均匀地分布文件,则可以在主线程中读取文件的块,并向块中提供原子偏移或指针。然后,每个附加线程可以一次分析较小的块并更新其统计信息。然后在所有线程加入时合并统计信息。

这样做可以让您按顺序读取文件,为您提供机械驱动器的性能优势,并在可用时立即执行工作,而无需担心线程的安排。

如果在线程之间均匀地分布工作并且不是最好的是一个很难的要求,你仍然可以检查文件大小,除以线程数量,并在它完成其部分时终止每个线程虽然还有很多事要做。但是其他一些线程将负责这项工作。

这种方法结合了顺序文件系统读取,为数据提供了map-reduce策略来计算结果。

另一种无锁方法是读取主线程中的块并使用循环法(对于偶数工作负载)将它们提供给每个线程的工作队列,或者检查哪个工作队列是最小的并放入它进入那里。

答案 3 :(得分:0)

以下是我将如何处理此问题并且无法保证正确,工作甚至编译的意识编码流。请注意,问题需要均匀分工,并且计算单词的方法是计算空格,从而节省了在处理之前读取整个文件的时间。 编辑:让它编译,似乎工作

#include <future>
#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
using namespace boost::filesystem;

struct Count
{
  size_t words;
  size_t letters;
  size_t punctuation;
  Count() : words(0), letters(0), punctuation(0){};
};

Count countData(const char *start, const char *end)
{
  Count count;
  for (auto data = start; data < end; data++)
  {
    if (ispunct(*data)) {count.punctuation++;}
    else if (isspace(*data)) {count.words++;}
    else if (isalpha(*data)) {count.letters++;}
  }
  return count;
}

int main(int argc, char* argv[])
{
  if (argc < 3)
  {
    return 1;
  }
  const char *filename = argv[2];
  const size_t numberThreads = std::max(std::stoi(argv[1]), 1);
  boost::iostreams::mapped_file_source file;
  std::vector<std::future<Count>> results;
  file.open(filename);
  if (file.is_open())
  {
    const size_t fileSize = file_size(filename);
    const size_t blockSize = fileSize/numberThreads;
    const char *dataStart= file.data();
    for (size_t i=0; i<numberThreads; i++)
    {
      const char *start = dataStart + i*blockSize;
      const char *end = dataStart + blockSize + i*blockSize;
      if (i == numberThreads-1) {end = dataStart + fileSize;}
      auto result = std::async(std::launch::async, [start, end]() {
          return countData(start, end);
        });
      results.emplace_back(std::move(result));
    }
  }
  else 
  {
    return 1;
  }
  size_t words = 0;
  size_t letters = 0;
  size_t punctuation = 0;
  for (auto &futureResult : results)
  {
    auto result = futureResult.get();
    words += result.words;
    letters += result.letters;
    punctuation += result.punctuation;
  }
  std::cout << "words : " << words << " letters : " << letters << " punctuation : " << punctuation << std::endl;
  return 0;
}