我有一个C ++脚本,它检查是否必须执行任何操作,如果是,则启动正确的处理器C ++脚本。但是,由于它每x分钟运行一次,它还会检查处理器是否仍在使用锁定文件运行。
我使用以下函数来获取锁:
int LockFile(string FileNameToLock) {
FileNameToLock += ".lock";
int fd = open(FileNameToLock.c_str(), O_RDWR | O_CREAT, 0666);
int rc = flock(fd, LOCK_EX | LOCK_NB);
if (rc || rc == -1) {
cout << errno << endl;
cout << strerror(errno) << endl;
return -1;
}
return fd;
}
正在执行的代码:
[...]
if (LockFile(ExecuteFileName, Extra) == -1) {
cout << "Already running!" << endl; //MAIN IS ALREADY RUNNING
//RETURNS ME Resource temporarily unavailable when processor is running from an earlier run
exit(EXIT_SUCCESS);
}
if (StartProcessor) { //PSEUDO
int LockFileProcessor = LockFile("Processor");
if (LockFileProcessor != -1) {
string Command = "nohup setsid ./Processor"; //NOHUP CREATES ZOMBIE?
Command += IntToString(result->getInt("Klantnummer"));
Command += " > /dev/null 2>&1 &"; //DISCARD OUTPUT
system(Command.c_str());
//STARTS PROCESSOR (AS ZOMBIE?)
}
}
首次运行 ,但是当主脚本再次运行 时,锁定文件会返回 - 1,表示发生错误(仅当处理器仍在运行时)。 errno为11,导致出现错误消息:Resource temporarily unavailable
。 请注意,这仅在(僵尸)处理器仍在运行时发生。 (但是,主脚本已经终止,应该关闭文件句柄吗?)
由于某种原因,僵尸将文件句柄保存到主脚本的锁文件中???
我不知道在哪里寻找这个问题。
解决: 看到我的回答
答案 0 :(得分:2)
不,11是EAGAIN/EWOULDBLOCK
,这只是意味着您无法获取锁定,因为资源已被锁定(请参阅the documentation)。由于LOCK_NB
标志,您收到了该错误(而不是阻止行为)。
编辑:经过一番讨论后,问题似乎是由于在子处理时保留了flock()
个锁。为避免此问题,我建议您不要在生命周期内使用flock()
,而是在退出时触摸并删除策略:
file.lock
存在,请退出file.lock
并开始处理file.lock
。当然这里有竞争条件。为了确保安全,您需要另一个flock
的文件:
flock(common.flock)
file.lock
存在,请退出file.lock
flock(common.flock)
file.lock
醇>
但是,只有当您希望同时拨打main
时,这才有意义。如果你没有(你说cron每10分钟启动一次这个过程,这里没有比赛)那么坚持第一个版本。
旁注:这里是这种(非同步)文件锁的简单实现:
#include <string>
#include <fstream>
#include <stdexcept>
#include <cstdio>
// for sleep only
#include <chrono>
#include <thread>
class FileLock {
public:
FileLock(const std::string& path) : path { path } {
if (std::ifstream{ path }) {
// You may want to use a custom exception here
throw std::runtime_error("Already locked.");
}
std::ofstream file{ path };
};
~FileLock() {
std::remove(path.c_str());
};
private:
std::string path;
};
int main() {
// This will throw std::runtime_error if test.xxx exists
FileLock fl { "./test.xxx" };
std::this_thread::sleep_for(std::chrono::seconds { 5 });
// RAII: no need to delete anything here
return 0;
};
需要C ++ 11。请注意,此实现不是竞争条件安全的,即您通常需要flock()
构造函数,但在这种情况下它可能没问题(即,当您不并行启动main时)。
答案 1 :(得分:0)
我解决了这个问题,因为系统和fork命令似乎通过保存命令在向量中执行来传递flock。在循环命令向量之前解锁锁定文件并执行每个命令。这使得主体在没有锁定的情况下具有非常小的运行间隙,但是现在看起来效果很好。这也支持不合理的终止。
[...]
if (LockFile(ExecuteFileName, Extra) == -1) {
cout << "Already running!" << endl; //MAIN IS ALREADY RUNNING
//RETURNS ME Resource temporarily unavailable when processor is running from an earlier run
exit(EXIT_SUCCESS);
}
vector<string> Commands;
if (StartProcessor) { //PSEUDO
int LockFileProcessor = LockFile("Processor");
if (LockFileProcessor != -1) {
string Command = "nohup setsid ./Processor"; //NOHUP CREATES ZOMBIE
Command += IntToString(result->getInt("Klantnummer"));
Command += " > /dev/null 2>&1 &"; //DISCARD OUTPUT
Commands.push_back(Command);
}
}
//UNLOCK MAIN
if (UnlockFile(LockFileMain)) {
for(auto const& Command: Commands) {
system(Command.c_str());
}
}