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

时间:2017-11-03 08:21:29

标签: c++ ubuntu system errno flock

我有一个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 请注意,这仅在(僵尸)处理器仍在运行时发生。 (但是,主脚本已经终止,应该关闭文件句柄吗?)

由于某种原因,僵尸将文件句柄保存到主脚本的锁文件中???

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

解决: 看到我的回答

2 个答案:

答案 0 :(得分:2)

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

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

  1. 如果file.lock存在,请退出
  2. 否则创建file.lock并开始处理
  3. 退出时删除file.lock
  4. 当然这里有竞争条件。为了确保安全,您需要另一个flock的文件:

    1. flock(common.flock)
    2. 如果file.lock存在,请退出
    3. 否则请创建file.lock
    4. 解锁flock(common.flock)
    5. 开始处理
    6. 退出
    7. 时删除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());
        }
    }
相关问题