2013-05-29 29 views
6

Nếu tôi sử dụng lệnh fopen() để mở cùng một tệp trong nhiều luồng và ghi dữ liệu vào tệp. Tôi có nên sử dụng một mutex để đảm bảo dữ liệu sẽ không bị rối loạn?Chức năng fopen() có an toàn trong Linux không?

+2

Vấn đề không phải là với fopen(), nhưng làm thế nào bạn viết thư cho tập tin. Bạn cần phải làm điều gì đó (một mutex là một ví dụ) để giữ cho các bài viết được kiểm soát. –

+0

"Ghi khóa" cũng là một tùy chọn. Nó cho phép bạn khóa phạm vi khác nhau của tập tin. Các chủ đề khác nhau có thể viết các phần khác nhau của tệp cùng một lúc. –

Trả lời

11

Nếu hai luồng đều mở cùng một tệp với fopen(), mỗi luồng sẽ có luồng tệp độc lập (FILE *) được hỗ trợ bởi các trình mô tả tệp độc lập đề cập đến cùng một tệp. Bạn có thể viết một cách độc lập với hai luồng tệp, nhưng kết quả ròng trên tệp sẽ phụ thuộc vào nơi các luồng ghi và khi chúng tuôn ra luồng tệp. Kết quả là không thể đoán trước trừ khi bạn kiểm soát vị trí của từng luồng. Điều đơn giản nhất là đảm bảo cả hai luồng đều sử dụng cùng một luồng tệp, nhưng bạn có thể vẫn cần phải phối hợp giữa các luồng. Lưu ý rằng POSIX đòi hỏi các chức năng C để cung cấp cho phối hợp quyền truy cập vào các dòng tập tin - xem flockfile() mà áp đặt yêu cầu rằng

Tất cả các chức năng mà tham khảo (FILE *) đối tượng, ngoại trừ những người có tên kết thúc bằng _unlocked, sẽ cư xử như thể họ sử dụng flockfile()funlockfile() nội bộ để có được quyền sở hữu của các đối tượng này (FILE *).

Nếu bạn mở tệp ở chế độ nối thêm trong cả hai chủ đề, thì bạn vẫn phải lo lắng về việc xóa dữ liệu trước khi bộ đệm lấp đầy.

+0

Tôi không chắc mình hiểu, nếu tôi truy cập (đọc/ghi) * các tệp khác nhau * cùng một lúc, tôi có nên gặp bất kỳ sự cố nào không? – ransh

+0

@ransh: Nếu hai luồng tệp được mở trên các tệp khác nhau, sẽ không có vấn đề gì. Nếu chúng được mở trên cùng một tệp, sẽ có vấn đề. –

+0

cảm ơn vì đã làm rõ. – ransh

1

Theo như tôi biết bạn nên sử dụng mutexes.

tôi đã không cố gắng này là C, nhưng trong Java nếu bạn mở một file trong hơn một thread, cả threads có thể viết trong đó và file thực sự là sai lầm.

Vì vậy, tôi nghĩ rằng tình huống trong C sẽ tương đương với Java.

+8

suy đoán không phải là câu trả lời hay. – stdcall

+0

Thực ra tôi đang nói rằng bạn nên thử nó. Chạy hai chủ đề và bạn sẽ thấy làm thế nào sai lầm lên các tập tin sẽ được. Tôi đang suy đoán điều gì? –

+3

"Vì vậy, tôi nghĩ rằng tình hình trong C sẽ tương đương với Java." - điều này có thể dễ dàng được viết dưới dạng nhận xét chứ không phải là câu trả lời. – stdcall

1

fopen() có thể nhập lại và bạn có thể có nhiều trình mô tả trỏ đến cùng một tệp như bạn muốn.

Những gì bạn nhận được do đọc/ghi từ/đến tệp bằng nhiều mô tả không phải là câu hỏi an toàn chủ đề, mà là truy cập tệp đồng thời, trong hầu hết các trường hợp (ngoài tệp khi chỉ đọc) sẽ không hoạt động tốt.

1

Dưới đây là một chủ đề an toàn mở tệp ghi, bạn có thể mở nhiều tệp và nó chỉ ghi vào tệp tuần tự. Tôi nghĩ rằng mã dưới đây có thể vẫn được tối ưu hóa với thời gian đồng bộ và popping ra các tập tin không sử dụng để duy trì bộ nhớ cache

Bất kỳ đề nghị được hoan nghênh

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