【发布时间】:2020-07-09 08:50:15
【问题描述】:
我有一个 PHP 脚本,它在 Linux 中接收发票并将其保存为文件。之后,一个基于 C++ 无限循环的程序读取每一个并进行一些处理。我希望后者安全地读取每个文件(仅在完全写入之后)。
PHP端代码简化:
file_put_contents("sampleDir/invoice.xml", "contents", LOCK_EX)
在 C++ 方面(使用 C 文件系统 API),我必须首先注意我想保留一个代码,该代码删除指定发票文件夹中的空文件,作为正确处理边缘情况的一种手段从其他来源(不是 PHP 脚本)创建的空文件。
现在,还有一个 C++ 端代码简化:
FILE* pInvoiceFile = fopen("sampleDir/invoice.xml", "r");
if (pInvoiceFile != NULL)
{
if (flock(pInvoiceFile->_fileno, LOCK_SH) == 0)
{
struct stat fileStat;
fstat(pInvoiceFile->_fileno, &fileStat);
string invoice;
invoice.resize(fileStat.st_size);
if (fread((char*)invoice.data(), 1, fileStat.st_size, pInvoiceFile) < 1)
{
remove("sampleDir/invoice.xml"); // Edge case resolution
}
flock(pInvoiceFile->_fileno, LOCK_UN);
}
}
fclose(pInvoiceFile);
如您所见,总结的关键概念是LOCK_EX 和LOCK_SH 标志的合作。
我的问题是,虽然这种集成工作正常,但昨天我注意到为不应为空的发票执行的边缘案例,因此它被 C++ 程序删除。
file_put_contents 上的 PHP 手册提到了 LOCK_EX 标志的以下内容:
在继续写入时获取文件的排他锁。换句话说,
flock()调用发生在fopen()调用和fwrite()调用 之间。这与模式为"x"的fopen()调用不同。
- 在
file_put_contents调用fopen之前没有建立LOCK_EX是否会导致问题作为竞争条件?如果是这样,在保留边缘案例删除代码的同时可以做些什么来解决这个问题? - 否则,我可能做错了什么吗?
【问题讨论】:
-
你的代码能在 Linux 上运行吗?
-
是的,这两种划分都具体运行在 CentOS 7 64 位系统上