こんにちは!今回はPHPのPOSIX拡張機能の中でも、シンプルで使いやすいposix_getpgrp関数について詳しく解説していきます。
posix_getpgrp関数とは?
posix_getpgrpは、現在のプロセスのプロセスグループID(PGID)を取得する関数です。posix_getpgidの簡易版で、自分自身のプロセスグループIDだけを取得します。
基本的な構文
posix_getpgrp(): int
- 引数: なし
- 戻り値: 現在のプロセスのプロセスグループID(整数)
posix_getpgidとの違い
この2つの関数は似ていますが、重要な違いがあります:
| 関数 | 引数 | 取得対象 | 用途 |
|---|---|---|---|
posix_getpgrp() | なし | 自分自身のPGID | 現在のプロセス情報のみ |
posix_getpgid($pid) | PID必須 | 指定したプロセスのPGID | 他のプロセスも調査可能 |
実質的には同じ
<?php
// この2つは同じ結果を返します
$pgrp1 = posix_getpgrp();
$pgrp2 = posix_getpgid(posix_getpid());
echo "posix_getpgrp(): {$pgrp1}\n";
echo "posix_getpgid(getpid()): {$pgrp2}\n";
if ($pgrp1 === $pgrp2) {
echo "✓ 両方とも同じ値を返しました\n";
}
?>
出力例:
posix_getpgrp(): 12340
posix_getpgid(getpid()): 12340
✓ 両方とも同じ値を返しました
基本的な使い方
シンプルな例
<?php
// 現在のプロセスグループIDを取得
$pgrp = posix_getpgrp();
$pid = posix_getpid();
echo "プロセスID: {$pid}\n";
echo "プロセスグループID: {$pgrp}\n";
if ($pid === $pgrp) {
echo "✓ このプロセスはグループリーダーです\n";
} else {
echo "- このプロセスはグループメンバーです\n";
echo " (グループリーダーのPIDは {$pgrp})\n";
}
?>
プロセス情報の表示
<?php
function displayProcessInfo(): void {
echo "=== 現在のプロセス情報 ===\n\n";
$pid = posix_getpid();
$ppid = posix_getppid();
$pgrp = posix_getpgrp();
$sid = posix_getsid(0);
$uid = posix_getuid();
$gid = posix_getgid();
echo "プロセス識別:\n";
echo " PID (プロセスID): {$pid}\n";
echo " PPID (親プロセスID): {$ppid}\n";
echo " PGRP (プロセスグループID): {$pgrp}\n";
echo " SID (セッションID): {$sid}\n\n";
echo "ユーザー/グループ:\n";
echo " UID (ユーザーID): {$uid}\n";
echo " GID (グループID): {$gid}\n\n";
echo "役割:\n";
if ($pid === $pgrp) {
echo " ✓ プロセスグループリーダー\n";
}
if ($pid === $sid) {
echo " ✓ セッションリーダー\n";
}
}
displayProcessInfo();
?>
実践的な活用例
1. プロセス監視ツール
<?php
class SimpleProcessMonitor {
public function getCurrentStatus(): array {
return [
'timestamp' => time(),
'pid' => posix_getpid(),
'ppid' => posix_getppid(),
'pgrp' => posix_getpgrp(),
'sid' => posix_getsid(0),
'is_group_leader' => (posix_getpid() === posix_getpgrp())
];
}
public function logStatus(string $logFile): bool {
$status = $this->getCurrentStatus();
$logEntry = sprintf(
"[%s] PID=%d PPID=%d PGRP=%d SID=%d Leader=%s\n",
date('Y-m-d H:i:s', $status['timestamp']),
$status['pid'],
$status['ppid'],
$status['pgrp'],
$status['sid'],
$status['is_group_leader'] ? 'YES' : 'NO'
);
return file_put_contents($logFile, $logEntry, FILE_APPEND) !== false;
}
public function printStatus(): void {
$status = $this->getCurrentStatus();
echo "=== プロセス状態 ===\n";
echo "時刻: " . date('Y-m-d H:i:s', $status['timestamp']) . "\n";
echo "PID: {$status['pid']}\n";
echo "PPID: {$status['ppid']}\n";
echo "PGRP: {$status['pgrp']}\n";
echo "SID: {$status['sid']}\n";
if ($status['is_group_leader']) {
echo "\n✓ このプロセスはグループリーダーです\n";
}
}
}
// 使用例
$monitor = new SimpleProcessMonitor();
$monitor->printStatus();
$monitor->logStatus('/tmp/process_monitor.log');
?>
2. グループ制御システム
<?php
class ProcessGroupController {
private int $pgrp;
public function __construct() {
$this->pgrp = posix_getpgrp();
}
public function isGroupLeader(): bool {
return posix_getpid() === $this->pgrp;
}
public function getGroupId(): int {
return $this->pgrp;
}
public function becomeGroupLeader(): bool {
// 新しいプロセスグループを作成し、自分がリーダーになる
if (posix_setpgid(0, 0)) {
$this->pgrp = posix_getpgrp();
return true;
}
return false;
}
public function sendSignalToGroup(int $signal): bool {
// プロセスグループ全体にシグナルを送信
// マイナスのPGIDを指定することでグループ全体に送信
return posix_kill(-$this->pgrp, $signal);
}
public function printGroupInfo(): void {
echo "=== プロセスグループ情報 ===\n";
echo "グループID: {$this->pgrp}\n";
echo "現在のPID: " . posix_getpid() . "\n";
echo "リーダー: " . ($this->isGroupLeader() ? 'YES' : 'NO') . "\n";
}
}
// 使用例
$controller = new ProcessGroupController();
$controller->printGroupInfo();
if (!$controller->isGroupLeader()) {
echo "\n新しいプロセスグループを作成します...\n";
if ($controller->becomeGroupLeader()) {
echo "✓ グループリーダーになりました\n";
$controller->printGroupInfo();
}
}
?>
3. ジョブ制御のシミュレーション
<?php
class JobController {
private array $jobs = [];
public function startJob(string $name, callable $task): ?int {
if (!function_exists('pcntl_fork')) {
echo "pcntl拡張が必要です\n";
return null;
}
$pid = pcntl_fork();
if ($pid === -1) {
return null;
}
if ($pid === 0) {
// 子プロセス
$myPid = posix_getpid();
$myPgrp = posix_getpgrp();
echo "[ジョブ {$name}] 開始 - PID: {$myPid}, PGRP: {$myPgrp}\n";
$task();
echo "[ジョブ {$name}] 完了\n";
exit(0);
}
// 親プロセス
$this->jobs[$pid] = [
'name' => $name,
'started_at' => time(),
'pgrp' => posix_getpgid($pid)
];
return $pid;
}
public function listJobs(): void {
echo "=== 実行中のジョブ ===\n";
echo "親プロセス PGRP: " . posix_getpgrp() . "\n\n";
foreach ($this->jobs as $pid => $job) {
$status = pcntl_waitpid($pid, $statusCode, WNOHANG);
$running = ($status === 0);
printf("%-20s PID: %5d PGRP: %5d 状態: %s\n",
$job['name'],
$pid,
$job['pgrp'],
$running ? '実行中' : '完了');
}
}
public function waitAll(): void {
foreach (array_keys($this->jobs) as $pid) {
pcntl_waitpid($pid, $status);
}
$this->jobs = [];
}
}
// 使用例
if (function_exists('pcntl_fork')) {
$jobController = new JobController();
// 複数のジョブを起動
$jobController->startJob('データ処理', function() {
sleep(2);
echo " データ処理実行中...\n";
});
$jobController->startJob('ファイル変換', function() {
sleep(1);
echo " ファイル変換実行中...\n";
});
$jobController->startJob('レポート生成', function() {
sleep(3);
echo " レポート生成実行中...\n";
});
sleep(1);
$jobController->listJobs();
echo "\n全ジョブの完了を待機中...\n";
$jobController->waitAll();
echo "✓ 全ジョブが完了しました\n";
}
?>
4. バックグラウンドタスクランナー
<?php
class BackgroundTaskRunner {
private string $taskLog;
public function __construct(string $taskLog = '/tmp/tasks.log') {
$this->taskLog = $taskLog;
}
public function runInBackground(callable $task, array $params = []): bool {
if (!function_exists('pcntl_fork')) {
echo "pcntl拡張が必要です\n";
return false;
}
$pid = pcntl_fork();
if ($pid === -1) {
return false;
}
if ($pid === 0) {
// 子プロセス
$this->logTask('start', $params);
try {
$task($params);
$this->logTask('success', $params);
} catch (Exception $e) {
$this->logTask('error', $params, $e->getMessage());
}
exit(0);
}
// 親プロセスはすぐに戻る(バックグラウンド実行)
return true;
}
private function logTask(string $status, array $params, string $message = ''): void {
$logEntry = sprintf(
"[%s] PID=%d PGRP=%d Status=%s Params=%s Message=%s\n",
date('Y-m-d H:i:s'),
posix_getpid(),
posix_getpgrp(),
$status,
json_encode($params),
$message
);
file_put_contents($this->taskLog, $logEntry, FILE_APPEND);
}
public function showTaskLog(int $lines = 10): void {
if (!file_exists($this->taskLog)) {
echo "タスクログが存在しません\n";
return;
}
$content = file($this->taskLog);
$content = array_slice($content, -$lines);
echo "=== 最新のタスクログ ({$lines}件) ===\n";
echo implode('', $content);
}
}
// 使用例
$runner = new BackgroundTaskRunner();
// タスク1: データベースのバックアップ
$runner->runInBackground(function($params) {
sleep(2);
echo "データベースバックアップ完了: {$params['database']}\n";
}, ['database' => 'myapp']);
// タスク2: 画像のサムネイル生成
$runner->runInBackground(function($params) {
sleep(1);
echo "サムネイル生成完了: {$params['image']}\n";
}, ['image' => 'photo.jpg']);
echo "✓ バックグラウンドタスクを開始しました\n";
echo "現在のプロセスグループID: " . posix_getpgrp() . "\n\n";
// ログの表示
sleep(3);
$runner->showTaskLog();
?>
よくある使用パターン
パターン1: グループリーダーのチェック
<?php
function amIGroupLeader(): bool {
return posix_getpid() === posix_getpgrp();
}
if (amIGroupLeader()) {
echo "✓ このプロセスはグループリーダーです\n";
echo " - グループ全体の制御が可能\n";
echo " - シグナルを受信してメンバーに伝播可能\n";
} else {
$leader = posix_getpgrp();
echo "- このプロセスはグループメンバーです\n";
echo " グループリーダー: PID {$leader}\n";
}
?>
パターン2: プロセス階層の確認
<?php
function showProcessHierarchy(): void {
$pid = posix_getpid();
$ppid = posix_getppid();
$pgrp = posix_getpgrp();
$sid = posix_getsid(0);
echo "プロセス階層:\n";
echo " セッション (SID: {$sid})\n";
echo " └─ プロセスグループ (PGRP: {$pgrp})\n";
echo " ├─ 親プロセス (PPID: {$ppid})\n";
echo " └─ 現在のプロセス (PID: {$pid}) ← YOU ARE HERE\n";
}
showProcessHierarchy();
?>
パターン3: シンプルなロギング
<?php
function logWithProcessInfo(string $message): void {
$logEntry = sprintf(
"[%s][PID:%d][PGRP:%d] %s\n",
date('Y-m-d H:i:s'),
posix_getpid(),
posix_getpgrp(),
$message
);
echo $logEntry;
error_log($logEntry);
}
// 使用例
logWithProcessInfo('アプリケーション起動');
logWithProcessInfo('データベース接続成功');
logWithProcessInfo('処理完了');
?>
posix_getpgid との使い分け
posix_getpgrp を使うべき場合
<?php
// ✅ 自分自身の情報だけが必要な場合
$myPgrp = posix_getpgrp();
// シンプルで分かりやすい
if (posix_getpid() === posix_getpgrp()) {
echo "グループリーダー\n";
}
?>
posix_getpgid を使うべき場合
<?php
// ✅ 他のプロセスの情報も必要な場合
$parentPgrp = posix_getpgid(posix_getppid());
$myPgrp = posix_getpgid(posix_getpid());
// 親プロセスとの比較
if ($myPgrp === $parentPgrp) {
echo "親と同じプロセスグループ\n";
} else {
echo "独立したプロセスグループ\n";
}
// ✅ 任意のプロセスを調査する場合
$targetPid = 1234;
$targetPgrp = posix_getpgid($targetPid);
?>
注意点とベストプラクティス
⚠️ 重要な注意事項
- POSIX環境限定: Windows環境では使用できません
- 常に成功: 自分自身の情報なので
falseを返すことはありません(環境が正しい限り) - シンプル: 引数がないので使いやすいが、他のプロセスは調べられない
環境チェック
<?php
function safeGetPgrp(): ?int {
if (!function_exists('posix_getpgrp')) {
error_log('POSIX拡張が利用できません');
return null;
}
return posix_getpgrp();
}
// 使用例
$pgrp = safeGetPgrp();
if ($pgrp !== null) {
echo "プロセスグループID: {$pgrp}\n";
} else {
echo "この環境ではPOSIX関数が利用できません\n";
}
?>
関連関数との比較
| 関数 | 引数 | 戻り値 | 用途 |
|---|---|---|---|
posix_getpgrp() | なし | 自分のPGID | シンプルに自分の情報を取得 |
posix_getpgid($pid) | PID | 指定プロセスのPGID | 他のプロセスも調査可能 |
posix_setpgid($pid, $pgid) | PID, PGID | 成功/失敗 | プロセスグループの設定 |
posix_getpid() | なし | 自分のPID | プロセスIDの取得 |
posix_getsid($pid) | PID | セッションID | より上位の階層 |
全関数の活用例
<?php
function comprehensiveProcessInfo(): void {
echo "=== 包括的なプロセス情報 ===\n\n";
// 基本情報
$pid = posix_getpid();
$ppid = posix_getppid();
// グループ情報(2つの方法)
$pgrp1 = posix_getpgrp();
$pgrp2 = posix_getpgid($pid);
$parent_pgrp = posix_getpgid($ppid);
// セッション情報
$sid = posix_getsid(0);
echo "プロセス識別子:\n";
echo " PID: {$pid}\n";
echo " PPID: {$ppid}\n\n";
echo "プロセスグループ:\n";
echo " posix_getpgrp(): {$pgrp1}\n";
echo " posix_getpgid(getpid()): {$pgrp2}\n";
echo " 親のPGRP: {$parent_pgrp}\n\n";
echo "セッション:\n";
echo " SID: {$sid}\n\n";
echo "検証:\n";
echo " 2つの方法で同じ結果: " . ($pgrp1 === $pgrp2 ? '✓ YES' : '✗ NO') . "\n";
echo " 親と同じグループ: " . ($pgrp1 === $parent_pgrp ? '✓ YES' : '✗ NO') . "\n";
echo " グループリーダー: " . ($pid === $pgrp1 ? '✓ YES' : '✗ NO') . "\n";
}
comprehensiveProcessInfo();
?>
まとめ
posix_getpgrp関数は、現在のプロセスのプロセスグループIDを取得するシンプルで使いやすい関数です。
特徴:
- ✅ 引数不要: 自分自身の情報だけをサッと取得
- ✅ シンプル:
posix_getpgid(posix_getpid())の省略形 - ✅ 高速: 最小限の処理で情報取得
- ✅ 信頼性: 自分自身の情報なので失敗しない
主な用途:
- グループリーダーかどうかの判定
- ログへのプロセス情報の記録
- プロセス階層の理解
- シンプルなプロセス監視
使い分けの基準:
- 自分の情報だけ →
posix_getpgrp()を使う - 他のプロセスも調査 →
posix_getpgid($pid)を使う
コンパクトで分かりやすいので、プロセス情報が必要な場面でまず最初に使いたい関数です!
参考リンク:
この記事が役立ったら、ぜひシェアしてください!⭐
