2014-11-05 73 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; 
}