2016-03-31 2 views
0

I 20 Threads in einem fange for-Schleife in eine Datei wie folgt zu schreiben:können nicht gleichzeitig schreiben, von mehr als 5 Fäden in Datei C++

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

Die searcher.start() Funktion beginnt der Thread, wird Führe das als Parameter übergebene Lambda aus. Das sf-Objekt besitzt die tatsächliche Datei, die von den Threads geschrieben wird, und einen Mutex, der in sf.writeLine() durch einen std :: lock_guard gesperrt ist.

Das Problem ist, dass nur 5 Threads gleichzeitig in die Datei geschrieben werden und nachdem einer von ihnen den Job beendet hat, beginnt der nächste gleichzeitig mit den anderen 4 Threads, die noch nicht fertig sind. Und so weiter, bis alle 20 Threads fertig sind.

Warum passiert das? Sollten nicht alle 20 Threads gleichzeitig in die Datei schreiben und nicht gleichzeitig 5? Hier

ist der vollständige Code:

Main:

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

FileSearcher.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 &); 
}; 

FileSearcher.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; 
} 
+0

Sie haben nur 5 Kerne? –

+4

Definieren Sie "nur 5 Threads schreiben gleichzeitig in die Datei". Die Sperre scheint zu jedem Zeitpunkt nur einem Thread das Schreiben in die Datei zu ermöglichen. –

+0

@ Siyuan Ren Ich habe 4 Kerne – whitefang1993

Antwort

0

Sie können das Timing des Kontextwechsels nicht bestimmen. es liegt an Betriebssystem. , aber Sie können den Kontext fragen, der zum Betriebssystem wechselt.

Aufruf std :: this_thread :: yield(); nach sf.writeLine (msg);

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); 
      std::this_thread::yield(); 
     } 
    }); 
+0

std :: this_thread :: yield() löste das Problem. – whitefang1993

Verwandte Themen