C++ Ubuntu 终止时不释放对锁定文件的锁定

C++ Ubuntu not releasing lock on lock file when terminated

我有一个 C++ 脚本,它检查是否需要执行任何操作,如果需要,它会启动正确的处理器 C++ 脚本。但是,由于它每 x 分钟 运行s,它还会检查处理器是否仍在 运行ning 使用锁定文件。

我使用以下函数获取锁:

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?)
        }
    }

第一个运行运行良好,但是当主脚本运行s ,锁定文件returns-1,表示发生错误(仅当处理器还在运行ning时)。 errno 是 11,这会导致错误消息:Resource temporarily unavailable请注意,这仅在(僵尸)处理器仍在 运行ning 时发生。 (但是,主脚本已经终止,应该关闭文件句柄?)

出于某种原因,僵尸保持打开主脚本的锁定文件的文件句柄???

我不知道去哪里找这个问题。

已解决: 看我的回答

不,11 是 EAGAIN/EWOULDBLOCK,这仅表示您无法获取锁,因为资源已被锁定(请参阅 the documentation)。由于 LOCK_NB 标志,您收到了该错误(而不是阻止行为)。

编辑: 经过一番讨论,问题似乎是由于子处理时 flock() 锁被保留所致。为避免此问题,我建议在整个生命周期内不要使用 flock(),而是使用触摸并删除退出策略:

  1. 如果file.lock存在则退出
  2. 否则创建file.lock并开始处理
  3. 在退出时删除 file.lock

这里当然存在竞争条件。为了确保安全,您需要另一个包含 flock:

的文件
  1. flock(common.flock)
  2. 如果file.lock存在则退出
  3. 否则创建file.lock
  4. 解锁flock(common.flock)
  5. 开始处理
  6. 在退出时删除 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 时)。

我解决了这个问题,因为 system 和 fork 命令似乎在群中传递,方法是保存要在向量中执行的命令。在循环命令向量之前解锁锁定文件并执行每个命令。这使得 main 在未锁定时有一个非常小的 运行 间隙,但现在它似乎工作得很好。这也支持非正常终止。

[...]
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());
        }
    }