我为我的操作系统作业解决了以下问题。我做了一些工作,但我还没到那里。非常感谢帮助。
问题
您的任务是创建一个多线程文档分析器。你的程序应该能够使用 处理提供的文件的可变线程数,并生成一些有关它的统计信息。该 所需数字是: • 单词数(通过计算空格数找到) • 字母数量(使用 因而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个线程连续读取它。请指出我正确的方向。
答案 0 :(得分:2)
您可以获取文件的长度并将该数字除以线程数。
然后,寻找每个潜在的起始位置(使用seekg()
)并通过读取下一个空格(std::isspace()
)进行调整,以避免将单词切成两半。
然后将每个开始和结束位置传递给一个线程(结束位置是以下分区的起始位置)。
然后每个线程使用seekg()
移动到其指定的位置,tellg()
确定它何时到达指定的结束位置。
答案 1 :(得分:0)
我的策略是:
找出文件中有多少单词,然后将该数字拆分为4
让每个线程读取文件的1/4。例如,如果文件中有80个单词:
答案 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;
}