开发者

Preventing deadlock caused by flock

开发者 https://www.devze.com 2023-02-28 15:57 出处:网络
I am trying to simulate a file writing on a busy site. I have written a following code which eventually end up freezing computer.

I am trying to simulate a file writing on a busy site. I have written a following code which eventually end up freezing computer.

$loop = 10000;
$sleep = 500000;
$i =0;

while($i < $loop) {

    $mtime = microtime();
    $mtime = explode(" ",$mtime);
    $mtime = $mtime[1] + $mtime[0];
    $starttime = $mtime; 

    开发者_运维知识库$handler = fopen($file,"a+");
    if($handler) {
    if (flock($handler, LOCK_EX)) {
        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $endtime = $mtime;
        $totaltime = ($endtime - $starttime); 

        fwrite($handler,"Script 1 took $totaltime secs\n");
    }

    flock($handler, LOCK_UN);
    fclose($handler);
}
$i++;
usleep($sleep);
}

I can't use LOCK_NB because it will not work on windows. The code works fine if there are less than 13 processes execute the above code at the same. How do I cope with this deadlock situation?


Reading your code, I'm thinking you should move flock($handler, LOCK_UN); inside the if (flock($handler, LOCK_EX)) {} conditional block.

To figure out exactly what's getting stuck and where, I would add datestamped (and flushed, so nothing gets stuck in the output buffer) debug output both before and after each call to flock(), fopen(), fwrite(), and fclose(), and redirect the output from each script instance to its own file.

Then, after a freeze + restart you can review the end of each file and see what each script was doing when you restarted. By comparing the datestamps you should be able to see which script(s) "froze" first.


Hy

Try with file_put_contents():

<?php

$file = 'file.txt';

$str = "some text\n";

file_put_contents($file, $str, FILE_APPEND | LOCK_EX);

?>


Before you write some more php code I recommend you use the application AB (apache benchmark) that comes with apache and simulate a high load in your local host EX>

ab -n 1000 -c 200 http://localhost/your.php

With this you can simulate 200 concurrent users and 1000 requests.


Try to "guard" the LOCK_EX with an additional mkdir() lock-mechanism as described here: https://stackoverflow.com/a/7927642/318765

Example:

<?php
$file = 'deadlock.txt';
$loop = 10000;
$sleep = 500000;
$i = 0;
while ($i < $loop) {
    $starttime = microtime(true);
    $handler = fopen($file, 'a+');
    if ($handler) {
        if (!file_exists($file . '_lock')) {
            if (mkdir($file . '_lock')) {
                if (flock($handler, LOCK_EX)) {
                    $endtime = microtime(true);
                    $totaltime = ($endtime - $starttime);
                    $totaltime = number_format($endtime - $starttime, 10);
                    if ($totaltime > 1) {
                        break;
                    }
                }
                flock($handler, LOCK_UN);
                fclose($handler);
                rmdir($file . '_lock');
            }
        }
    }
    $i++;
    usleep($sleep);
}
?>

As you can see I added a break; to avoid the deadlock. If the scripts stops you can view into the log file.

In Linux I'm using this mkdir() trick without flock() as it is atomic. I don't know if this works in Windows, too.

0

精彩评论

暂无评论...
验证码 换一张
取 消