在PHP的多進程編程中,pcntl_waitpid函數是一個非常重要的函數。它可以等待子進程的退出并返回狀態碼,從而實現進程間的同步。
假設我們有一個多進程爬蟲程序,同時啟動了多個子進程并發執行。每個子進程爬取一個不同的網頁并將結果保存到文件中。那么如何在主進程中等待所有子進程完成任務再進行下一步操作呢?這時候就可以使用pcntl_waitpid函數。
foreach ($urls as $url) {
$pid = pcntl_fork();
if ($pid == -1) {
// fork失敗
} elseif ($pid == 0) {
// 子進程執行任務
spider($url);
exit;
} else {
// 父進程繼續循環
}
}
// 等待所有子進程退出
while (pcntl_waitpid(-1, $status) != -1) {
$exitStatus = pcntl_wexitstatus($status);
echo "子進程退出,狀態碼為$exitStatus\n";
}
上面的代碼中,我們先啟動了多個子進程并發執行任務。當爬蟲任務執行完成后子進程會調用exit函數退出,父進程則繼續循環啟動下一個子進程。而在所有子進程都退出后,父進程進入while循環,等待子進程的退出并輸出每個子進程的狀態碼。
pcntl_waitpid函數的參數非常重要,它決定了這個函數的行為。參數一指定要等待的子進程ID,-1表示等待任何子進程。參數二會被修改為子進程的退出狀態碼,通過pcntl_wexitstatus函數可以獲取到具體的狀態碼。如果出錯,pcntl_waitpid函數會返回-1。
還有一點需要注意的是,當一個子進程的狀態碼被取出后,它就會被操作系統回收掉。如果我們想要保留子進程的一些調試信息,可以在子進程退出前,將需要的信息寫入IPC共享內存或管道中。
foreach ($urls as $url) {
$pid = pcntl_fork();
if ($pid == -1) {
// fork失敗
} elseif ($pid == 0) {
// 子進程執行任務
spider($url);
// 將爬取結果寫入共享內存
$shm_key = ftok(__FILE__, 'a');
$shm_id = shmop_open($shm_key, 'c', 0666, 1024);
shmop_write($shm_id, $url . "爬取結束\n", 0);
shmop_close($shm_id);
exit;
} else {
// 父進程繼續循環
}
}
// 等待所有子進程退出
while (pcntl_waitpid(-1, $status) != -1) {
$exitStatus = pcntl_wexitstatus($status);
// 從共享內存中取出爬取結果
$shm_key = ftok(__FILE__, 'a');
$shm_id = shmop_open($shm_key, 'a', 0, 0);
$data = shmop_read($shm_id, 0, 1024);
shmop_delete($shm_id);
shmop_close($shm_id);
echo "$data\n子進程退出,狀態碼為$exitStatus\n";
}
上面的代碼中,我們將爬取結果寫入共享內存中,并在子進程退出后從共享內存中取出結果輸出。這樣我們就可以保留子進程的一些有用信息。
總結來說,pcntl_waitpid函數可以實現進程間的同步,等待指定的子進程退出并返回狀態碼。在使用時需要注意該函數的參數,以及子進程退出后會被操作系統回收掉的事實。