2013-05-29 8 views
6

Jeśli używam wywołania fopen(), aby otworzyć ten sam plik w wielu wątkach i zapisać dane do pliku. Czy powinienem użyć muteksa, aby upewnić się, że dane nie zostaną zakłócone?Czy funkcja fopen() jest wątkiem bezpiecznym w systemie Linux?

+2

Problem nie jest z fopen(), ale jak piszesz plik. Musisz coś zrobić (mutex jest jednym z przykładów), aby zachować pisownię pod kontrolą. –

+0

"Blokada zapisu" jest również opcją. Umożliwia zablokowanie różnych zakresów pliku. Różne wątki mogą zapisywać różne części pliku w tym samym czasie. –

Odpowiedz

11

Jeśli dwa wątki otwierają ten sam plik z fopen(), będą miały niezależne strumienie plików (FILE *) wspierane przez niezależne deskryptory plików odnoszące się do tego samego pliku. Możesz napisać niezależnie do dwóch strumieni plików, ale wynik netto w pliku będzie zależał od tego, gdzie pisze wątek i kiedy przepłukuje strumień plików. Rezultaty są nieprzewidywalne, chyba że kontrolujesz, gdzie pisze każdy wątek. Najprościej jest upewnić się, że oba wątki używają tego samego strumienia plików, ale prawdopodobnie nadal musisz skoordynować wątki. Zauważ, że POSIX wymaga funkcji C otrzymując skoordynowany dostęp do strumienia pliku - patrz flockfile() który nakłada wymóg

Wszystkie funkcje, które odwołują (FILE *) obiektów, z wyjątkiem tych, których nazwa kończy się _unlocked, powinien zachowywać się tak, jakby używać flockfile() i funlockfile() wewnętrznie, aby uzyskać własność tych obiektów (FILE *).

Jeśli otworzysz plik w trybie dopisywania w obu nitek, wówczas zapisy byłoby bezpiecznie na końcu pliku za każdym razem, ale nadal trzeba się martwić o spłukiwania dane przed bufor zapełnia.

+0

Nie jestem pewien, czy zrozumiałem, jeśli mam dostęp (odczyt/zapis) * różnicować * pliki w tym samym czasie, czy powinienem się spodziewać jakiegoś problemu? – ransh

+0

@ransh: Jeśli dwa pliki strumieniowe są otwierane w różnych plikach, nie będzie problemu. Jeśli zostaną otwarte na tym samym pliku, wystąpią problemy. –

+0

dzięki za wyjaśnienia. – ransh

1

Z tego co wiem, powinieneś użyć mutexes.

ja nie spróbować to C, ale w Java jeśli otworzysz file w więcej niż jednym thread zarówno threads może pisać w nim i file jest naprawdę pomieszane.

Więc myślę, że sytuacja w C będzie odpowiednikiem Java.

+8

spekulacje nie są dobre odpowiedzi – stdcall

+0

Właściwie mówię, że powinieneś spróbować. Uruchom dwa wątki, a zobaczysz, jak pomieszane będą pliki. Co ja spekuluję? –

+3

"Więc myślę, że sytuacja w C będzie równoważna z Javą." - można to łatwo zapisać jako komentarz, a nie jako odpowiedź. – stdcall

1

ponownie można, a ty możesz mieć tylu deskryptorów wskazujących na ten sam plik, jak chcesz.

To, co dostajesz w wyniku odczytu/zapisu z/do pliku przy użyciu wielu deskryptorów, nie jest pytaniem o bezpieczeństwo wątków, ale raczej współbieżnym dostępem do plików, które w większości przypadków (z wyjątkiem sytuacji, gdy plik jest tylko do odczytu) nie będzie działać dobrze.

1

Poniżej znajduje się wątek bezpieczny otwarty plik zapisu, można otworzyć wiele plików i po prostu pisać do pliku sekwencyjnie. myślę poniższy kod może być jeszcze optymalizowana z synchronizacją czasu i wychodziły nieużywane pliki, aby utrzymać buforuje

Każda sugestia jest mile widziany

class OpenFile 
{ 
    string fileName; 
    static map<string, unique_ptr<mutex>> fmap; 
    bool flag; 
public : 
    OpenFile(string file) : fileName(file) { 
     try { 
      if(checkFile(file)) 
      { 
       flag = false; 
       fmap.emplace(file, make_unique<mutex>()); 
      } 
      else 
      { 
       flag = true; 
      } 
     } 
     catch(string str) 
     { 
      cout << str << endl; 
     } 
    } 
    void writeToFile(const string& str) const 
    { 
     if (flag) 
     { 
      lock_guard<mutex> lck(*fmap.find(fileName)->second); 
      ofstream ofile(fileName, ios::app); 
      ofile << "Writing to the file " << str << endl; 
      ofile.close(); 
     } 
     else 
     { 
      ofstream ofile(fileName, ios::app); 
      ofile << "Writing to the file " << str << endl; 
      ofile.close(); 
     } 
    } 
    string ReadFile() const 
    { 
     string line; 
     if (flag) 
     { 
      lock_guard<mutex> lck(*fmap.find(fileName)->second); 
      ifstream ifile(fileName, ios::in); 
      getline(ifile, line); 
      ifile.close(); 
     } 
     else 
     { 
      ifstream ifile(fileName, ios::in); 
      getline(ifile, line); 
      ifile.close(); 
     } 
     return line; 
    } 
    OpenFile() = delete; 
    OpenFile& operator=(const OpenFile& o) = delete; 
    static bool checkFile(string& fname); 
}; 


bool OpenFile::checkFile(string& fname) 
{ 
    if (fmap.find(fname)==fmap.end()) 
    { 
     return true; 
    } 
    else 
     return false; 
}