2014-11-05 31 views
1

我必须为我的操作系统作业解决以下问题。我做了一些工作,但我还没有完成。帮助将不胜感激。如何使用多线程读取文件?

问题

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

这是到目前为止我的代码

#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个线程连续读取。请指向正确的方向。

+0

可能打开该文件中的每个线程读取文件(除以线程数)的不同部分,并计算上有什么阅读统计线程。然后结合所有线程的结果。 – drescherjm 2014-11-05 16:52:35

+0

我会使用mmap()映射文件一次,然后启动线程并使它们从特定位置(文件中的0%,25%,50%和75%)读取。 – 2014-11-05 16:53:36

回答

2

你可以获取该文件的长度,并分割成数的线程数。

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

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

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

+0

是否需要资源锁才能阻止一个线程读取其他线程的节? – 2014-11-05 19:30:19

+0

@ThomasMatthews号每个线程正在阅读一个单独的部分。他们也应该打开他们自己的文件描述符,所以共享缓冲区应该没有问题。 – Galik 2014-11-05 19:45:52

+0

@Galik谢谢大家花时间和帮助我,但是这很简单:-) – LoXatoR 2014-11-08 20:34:47

0

我的策略是:

  1. 发现有多少话是在该文件中,然后拆分成数4

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

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

是的,但我的问题是如何将它分成4个部分? – LoXatoR 2014-11-05 16:53:00

+0

http://www.cplusplus.com/reference/istream/istream/seekg/或内存映射文件 – drescherjm 2014-11-05 16:54:43

0

应该还是必须将文档在线程之间平均分配? 如果他们应该这样做,你会有一个更容易的工作,获得性能增益,并理论上读取任意大文件,而不必并行访问文件系统,这是一个坏主意,因为它很难达到性能。

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

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

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

该方法结合了顺序文件系统读取以提供数据和地图缩减策略来计算结果。

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

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; 
}