Search code examples
c++ubuntusystemerrnoflock

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


I have a C++ script, which checks whether any action has to be done and if so it starts the right processor C++ script. However, since it runs every x minutes it also checks whether the processor isn't still running using lock files.

I use the following function to acquire the lock:

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;
    }

The code that is being executed:

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

The first run works well, however when the main script runs again, the lock file returns -1, which means an error occurred (only when the processor is still running). The errno is 11 which results in the error message: Resource temporarily unavailable. Note that this only happens when the (zombie) processor is still running. (However, the main script has already terminated, which should close the file handle?)

For some reason, the zombie keeps the file handle to the lock file of the main script open???

I have no idea where to look for this problem.

SOLVED: see my answer


Solution

  • I solved this issue, since the system and fork commands seem to pass on the flock, by saving the command to execute in a vector. Unlock the lock file right before looping the Commands vector and execute each command. This leaves the main with a very tiny gap of running while not locked, but for now it seems to work great. This also supports ungraceful terminations.

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