简体   繁体   中英

File locking between C++ and PHP

I'm creating a somewhat silly but effective way to create jobs in PHP, that C++ then picks up. The job files created by PHP are simply text files that C++ reads out line by line, adding each line to a vector.

Folders:

  1. "jobs" -> New job files end up in here
  2. "jobhold" -> Job files are moved here once C++ starts working on them.
  3. "jobstime" -> Holds files with a name identical to the jobfile, containing EPOCH time so I can check how much time passed since last we did this job.

The problem: PHP assumes a file isn't being handled by C++ while it's in "jobhold" but C++ really only moved it there to prevent the job from being executed twice (as shown below). C++ still needs to read the file to put it's contents in a vector, so I need to prevent PHP from accessing this file while this happens.

Also, I need to disallow C++ from handling a job file in the "jobhold" folder while it's being edited by PHP.

The C++ function that checks if enough time has passed since we last did this job :

  1. Open the jobstime file and determine if X seconds have passed since last we did this job
  2. IF enough time passed:
  3. move jobfile from "jobhold" to "jobs" so the next function creates a thread for it that executes the job.
  4. remove corresponding time file from "jobstime", it will be recreated in the thread, which is created in the next function.

-> I need to cancel these 2 steps (3 & 4) if PHP has a lock on the file . Which would mean the file is completely ignored until PHP is done with it.

The C++ function that handles the files in the "jobs" folder :

  1. Moves the jobfile from "jobs" back to "jobhold", this prevents the thread from being created twice.
  2. Creates time file in "jobstime" containign the current time (EPOCH)
  3. Creates new thread that's going to handle the file (just passes the filename to the new thread so it knows which file to handle)

-> I need to make sure PHP can't handle the file yet, even though it's in "jobhold" . C++ needs to immediately lock it (after, during, before? ) so there is no chance whatsoever that PHP can pick the file up, and not release it until somewhere inside the thread.

C++ Thread that handles the jobfile:

  1. The jobfile (which is currently in the "jobhold" folder) is read out, and each line is added to a vector created by the thread.

-> After this step, the file lock can be released , at which point PHP can lock the file so C++ won't handle it anymore.

PHP (currently only checks if the file in "jobhold" exists ):

<?php
if(isset($_GET['edit'])) 
{
    $filename = $startdir.'jobhold/'.$_GET['edit'];
    while (!file_exists($filename)) 
    {
        while(file_exists($startdir.'jobs/'.$_GET['edit']))
        {
            //Wait until C++ moves the file from "jobs" to "jobhold" by doing nothing
        }

        if(file_exists(filename)
        {
            break 1; //The file exists now, we may break the while.
        }

        //If we reached this point, the job simply doesn't exist.. so die.
        echo "The job $_GET[edit] doesn't exist. <br /><br />";
        die();
    }
}
/* Other code here, such as HTML form so user can edit the txt file */
?>

-> Need to add another check in PHP that checks if C++ has a lock on the jobfile in "jobhold". If yes, wait until the lock is removed and then immediately lock the file so C++ can't handle it anymore. Like so (silly example):

<?php
    while(file_locked_by_c++($startdir.'jobshold/'.$_GET['edit']))
    {
        //Wait until C++ releases the file by doing nothing
    }
    /* Lock file NOW */
?>

I did find this thread , and although I don't mind using C in my C++ code, I didn't manage to figure out how to apply that questions answer to my situation without a proper example.

PS : The reason I'm not posting any actual C++ code is because I'd get flamed for the (sometimes messy but mostly redundant) way I code because I'm new to C++, and that would just confuse other newbies and/or take away from what I'm trying to achieve here.

If you insist on seeing some code, that's fine, but please don't mention the mess / redundancy because I already know , they're just cheap workarounds that I will "fix" in a later stage. And if you're a newbie, make sure not to copy these mistakes.

pastebin

Sorry for such a long post for something so simple, but I need to get this 100% right or the entire application may break.

UPDATE:

I am currently doing this:

Added a new folder called "lock" which will contain files like php-jobnameX.txt and c-jobnameX.txt where jobnameX is the name of the current job.

C++:

-. When C++ checks if enough time has passed since last we did the jobfile in "jobhold", prior to moving the file from "jobhold" to "jobs" it first checks if php has created a file in "lock". If it did, we skip the file.

//This function will check if PHP has created a lock-file
bool checkifphplock(char* filename)
{
    ifstream fin(filename);
    if (fin)
    {
       fin.close();
       return true;
    }
    return false;
}

int cont = 1;
if(checkifphplock(phplockfile))
{
    cont = 0; //php lock found, so we go byebye
}

if(cont == 1)
{
  /* Keep doing stuff */
}

-. When php starts working on the jobfiles in "jobs", prior to moving the jobfile from "jobs" back to "jobhold", it creates a lock file in "lock" to notify php it's still working on the file.

ofstream myfileclock;
myfileclock.open (clockfile, fstream::in | fstream::out | fstream::app);
myfileclock << " ";
myfileclock.close();

-. Once the c++ thread is done copying the file contents to a vector, the lock file is removed to notify PHP it's ready to be edited again.

system("rm /path/to/program/lock/c-jobnameX.txt");

PHP:

-. Upon edit, obtain lock immediately by creating a file in "lock".

//Obtain lock immediately:
$file = $startdir."lock/php-$_GET[edit]";
if(!is_file($file)){ file_put_contents_atomic($file," "); chmod($file,0777);} //Make file if there is none
if(!is_writable($file)){chmod($file.'/',0777);} //Chmod file if not writable
if(!is_writable($file)){die("File \"$file\" not writable.");} //Die if not writable

-. After obtaining the lock, double check if c++ doesn't have a lock file as well (in case both C++ and PHP requested the jobfile at the exact same time)

while (file_exists($startdir."lock/c-$_GET[edit]")) 
{
    //Do nothing while c/c++ has a lock
}

-. In case c++ already moved the file from "jobhold" to "jobs", we wait until it's moved back.

//Wait for filename to exist in jobhold. Or die if it doesn't exist in any folder.
$filename = $startdir.'jobhold/'.$_GET['edit'];
while (!file_exists($filename)) 
{
    while(file_exists($startdir.'jobs/'.$_GET['edit']))
    {
        //Wait until C++ moves the file from "jobs" to "jobhold" by doing nothing
    }

    if(file_exists($filename))
    {
        break 1; //The file exists now, we may break the while.
    }

    //If we reached this point, the job simply doesn't exist.. so die.
    echo "The job $_GET[edit] doesn't exist. <br /><br />";
    unlink($file); //Remove lock for this non-existing job
    die();
}
/* Continue creating form to edit the file etc. */

Technically that last step should never be possible because the file can't (shouldn't) be in "jobs" if C/C++ doesn't have a lock, but it doesn't hurt to check.

Will doing this make 100% sure PHP and C/C++ can't both handle the file at the same time?

An extremely simple method of file locking is to have a line at the top of the files which reads locked or what ever you like. Each piece of code checks to see if that line is there before doing anything. The first and last action on the file is to lock/unlock the file by adding the word locked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM