«

php多进程编程进程间问题-谨慎处理共享资源的访问,避免竞态条件

时间:2023-10-16 21:58     作者:wanzi     分类: php



hi, 大家好,今天分享一个常见多进程编程的基础bug问题。

问题

在多进程环境中使用 mkdir() 函数创建目录时可能会出现PHP Warning: mkdir(): File exists

$numberOfProcesses = 10;

for ($i = 0; $i < $numberOfProcesses; $i++) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        // 处理创建进程失败的情况
        exit("Failed to create child process.");
    } elseif ($pid == 0) {
        // 子进程代码
        echo "Child process " . getmypid() . " started.\n";
        // 执行子进程的任务
        if (!is_dir('./test')) {
            mkdir('./test', 0777);
        }
        echo "Child process " . getmypid() . " finished.\n";
        exit(); // 子进程结束
    } else {
        // 父进程继续创建下一个子进程
        continue;
    }
}

// 等待所有子进程结束
while (pcntl_waitpid(0, $status) != -1) {
    $status = pcntl_wexitstatus($status);
    echo "Child process $status finished.\n";
}
$numberOfProcesses = 20;

for ($i = 0; $i < $numberOfProcesses; $i++) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        // 处理创建进程失败的情况
        exit("Failed to create child process.");
    } elseif ($pid == 0) {
        // 子进程代码
        echo "Child process " . getmypid() . " started.\n";
        // 执行子进程的任务
        if (!is_dir('./test') && mkdir('./test', 0777)) 
        echo "Child process " . getmypid() . " finished.\n";
        exit(); // 子进程结束
    } else {
        // 父进程继续创建下一个子进程
        continue;
    }
}

// 等待所有子进程结束
while (pcntl_waitpid(0, $status) != -1) {
    $status = pcntl_wexitstatus($status);
    echo "Child process $status finished.\n";
}

产生原因

由于并发的特性,多个进程同时判断目录是否存在,然后尝试创建目录,可能会出现竞争条件。当一个进程判断目录不存在时,另一个进程可能在此之前已经创建了该目录,导致当前进程执行 mkdir() 函数时报错

解决办法

$numberOfProcesses = 20;

for ($i = 0; $i < $numberOfProcesses; $i++) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        // 处理创建进程失败的情况
        exit("Failed to create child process.");
    } elseif ($pid == 0) {
        // 子进程代码
        echo "Child process " . getmypid() . " started.\n";
        // 执行子进程的任务
        $lockFile = 'lockfile.lock';
        $lockHandle = fopen($lockFile, 'w');
        if (flock($lockHandle, LOCK_EX)) {
            if (!is_dir('./test2')) {
                mkdir('./test2', 0777);
            }

            flock($lockHandle, LOCK_UN);
        }

        fclose($lockHandle);

        echo "Child process " . getmypid() . " finished.\n";
        exit(); // 子进程结束
    } else {
        // 父进程继续创建下一个子进程
        continue;
    }
}

// 等待所有子进程结束
while (pcntl_waitpid(0, $status) != -1) {
    $status = pcntl_wexitstatus($status);
    echo "Child process $status finished.\n";
}

标签: php