【发布时间】:2016-07-19 21:44:06
【问题描述】:
我正在一个 for 循环中启动 20 个线程来写入这样的文件:
for (FileSearcher & searcher : searchers)
{
searcher.start([&sf](std::string & fileName, int & id)
{
for (int i = 1; i < 100; i++)
{
//sf << "T " << id << " " << fileName << i << "\n";
std::string msg("T ");
msg += std::to_string(id);
msg += " ";
msg += fileName;
msg += std::to_string(i);;
msg += "\n";
sf.writeLine(msg);
}
});
searcher.start() 函数启动线程,该线程将执行作为参数传递的 lambda。 sf 对象拥有由线程写入的实际文件和一个由 sf.writeLine() 中的 std::lock_guard 锁定的互斥锁。
问题在于只有 5 个线程同时写入文件,其中一个线程完成工作后,下一个线程开始与其他 4 个尚未完成的线程同时写入。以此类推,直到所有 20 个线程都完成。
为什么会这样?不是应该所有 20 个线程同时写入文件,而不是一次写入 5 个吗?
完整代码如下:
主要:
#include <iostream>
#include "FileSearcher.h"
#include "SafeFileStream.h"
int main()
{
SafeFileStream sf("D:\\x.txt");
//sf.writeLine("hellow");
FileSearcher searchers[20];
for (int j = 0; j < 20; j++)
{
searchers[j].setFileName("Some file name.txt");
searchers[j].setId(j);
}
for (FileSearcher & searcher : searchers)
{
searcher.start([&sf](std::string & fileName, int & id)
{
for (int i = 1; i < 100; i++)
{
//sf << "T " << id << " " << fileName << i << "\n";
std::string msg("T ");
msg += std::to_string(id);
msg += " ";
msg += fileName;
msg += std::to_string(i);;
msg += "\n";
sf.writeLine(msg);
}
});
}
for (FileSearcher & searcher : searchers)
{
searcher.join();
}
return 0;
}
文件搜索器.h
#include <thread>
#include <string>
#include <functional>
#include <fstream>
class FileSearcher {
private:
std::unique_ptr<std::thread> searcher;
std::string fileName;
std::ifstream inputFile;
int id;
public:
FileSearcher();
FileSearcher(const int &, const std::string &);
~FileSearcher();
void start(std::function<void(std::string &, int &)>);
void join();
void setFileName(const std::string &);
void setId(const int &);
};
文件搜索器.cpp
#include "FileSearcher.h"
FileSearcher::FileSearcher() {}
FileSearcher::FileSearcher(const int & id, const std::string & fileName)
{
this->fileName = fileName;
this->id = id;
}
FileSearcher::~FileSearcher()
{
if (this->searcher->joinable())
{
this->searcher->join();
}
}
void FileSearcher::setFileName(const std::string & fileName)
{
this->fileName = fileName;
}
void FileSearcher::setId(const int & id)
{
this->id = id;
}
void FileSearcher::start(std::function<void(std::string &, int & id)> searchingMethod)
{
this->inputFile.open(this->fileName);
this->searcher = std::unique_ptr<std::thread>(new std::thread(searchingMethod, std::ref(this->fileName), std::ref(this->id)));
}
void FileSearcher::join()
{
if (this->searcher->joinable())
{
this->searcher->join();
}
}
SafeFileStream.h
#include <fstream>
#include <string>
#include <mutex>
#include <iostream>
class SafeFileStream
{
private:
std::ofstream outputFile;
std::string fileName;
std::mutex mu;
std::unique_ptr<std::lock_guard<std::mutex>> lockGuard;
std::unique_lock<std::mutex> uniqueLocker;
std::unique_ptr<std::thread> safeQueueHandler;
public:
SafeFileStream(std::string);
SafeFileStream(SafeFileStream&&);
~SafeFileStream();
template <typename T> void writeLine(T);
template <typename T> void write(T msg);
};
SafeFileStream::SafeFileStream(std::string fileName) : fileName(fileName)
{
this->outputFile.open(fileName);
}
SafeFileStream::SafeFileStream(SafeFileStream&& sfFileStream)
{
this->fileName = sfFileStream.fileName;
}
SafeFileStream::~SafeFileStream()
{
this->outputFile.close();
}
template <typename T> void SafeFileStream::writeLine(T msg)
{
std::lock_guard<std::mutex> lockGuard(this->mu);
this->outputFile << msg << "\n";
}
template <typename T> void SafeFileStream::write(T msg)
{
std::lock_guard<std::mutex> lockGuard(this->mu);
this->outputFile << msg;
}
【问题讨论】:
-
你只有 5 个核心?
-
定义“只有 5 个线程同时写入文件”。锁似乎只允许一个线程在任何给定时间写入文件。
-
@Siyuan Ren 我有4核
-
@Sam Varshavchik “只有 5 个线程同时写入文件” - 我的意思是 5 个线程同时写入文件。其他15个是被动的。如果其中一个活动线程完成写入,则其中一个被动线程激活并开始与其他 4 个活动线程同时写入。
-
据我所知,该标准不保证线程调度中的“公平性”,或者等待互斥体的线程将以任何特定顺序获得它的所有权。
标签: c++ multithreading