如果我使用 fopen() 调用在多线程中打开同一个文件,并将数据写入文件。我应该使用互斥锁来确保数据不会混乱吗?
4 回答
如果两个线程都用 来打开同一个文件fopen()
,那么它们每个都有独立的文件流 ( FILE *
),由引用同一文件的独立文件描述符支持。您可以独立地写入两个文件流,但文件的最终结果将取决于线程写入的位置以及它们何时刷新文件流。除非您控制每个线程的写入位置,否则结果是不可预测的。最简单的事情是确保两个线程使用相同的文件流,但您可能仍需要在线程之间进行协调。请注意,POSIX 要求 C 函数提供对文件流的协调访问 - 看看flockfile()
哪个强加了以下要求
所有引用
(FILE *)
对象的函数(名称以 结尾的函数除外)的_unlocked
行为应如同它们使用flockfile()
并funlockfile()
在内部获取这些 (FILE *) 对象的所有权一样。
如果您在两个线程中以附加模式打开文件,那么每次写入都将安全地位于文件的末尾,但您仍然需要担心在缓冲区填满之前刷新数据。
顺便说一句,如果您以追加模式(O_APPEND
with open()
,使用"a"
with fopen()
)打开文件,那么所有写入都应该在文件的末尾,并且您不应该遇到交错写入的麻烦 - 除非您的独立线程正在使用文件流并一次写入多个缓冲区,或者它们fflush()
在写入每行输出的部分后使用,或者它们正在使用write()
或其无数亲戚中的一个每次写入一行的一部分。即使使用附加模式,也有一些方法会遇到问题,但您通常必须尝试遇到它们。
fopen()
是可重新输入的,你可以有任意多的描述符指向同一个文件。
使用多个描述符读取/写入文件所得到的结果不是线程安全问题,而是并发文件访问,在大多数情况下(除了文件是只读的)不会工作出色地。
据我所知,您应该使用mutexes
.
我没试过这个C
,但是Java
如果你打开一个file
以上的thread
,两个都threads
可以写进去,file
真的很乱。
所以我认为中的情况C
将相当于Java
。
下面是一个线程安全的打开文件写入,您可以打开多个文件,它只是按顺序写入文件。我认为下面的代码仍然可以通过时间同步和弹出未使用的文件来维护缓存进行优化
欢迎任何建议
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;
}