摘要:本文描述的是Linux手册页中setpgid()、getpgid()、setpgrp()和getpgrp()函数的使用说明.原文来自:http://www.kernel.org/doc/man-pages/.
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); /* POSIX.1 version */
pid_t getpgrp(pid_t pid); /* BSD version */
int setpgrp(void); /* System V version */
int setpgrp(pid_t pid, pid_t pgid); /* BSD version */
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
getpgid():
_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
setpgrp() (POSIX.1):
_SVID_SOURCE || _XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.19: */ _BSD_SOURCE
setpgrp() (BSD), getpgrp() (BSD) [before glibc 2.19]:
_BSD_SOURCE &&
! (_POSIX_SOURCE || _POSIX_C_SOURCE || _XOPEN_SOURCE ||
_XOPEN_SOURCE_EXTENDED || _GNU_SOURCE || _SVID_SOURCE)
setpgid()函数将pid进程的进程组ID(PGID)设置为pgid.如果pid是0,则使用调用者的进程ID.如果pgid是0,则由pid指定的进程ID(PID)将用作进程组ID(PGID).如果使用setpgid()函数将某进程组的一个进程指定到另一个进程组,则要求两个进程组是属于同一个会话.在这种情况下,进程和进程组的会话(ID)相同,进程可以加入到由pgid指定的进程组中.
在POSIX.1标准中,getpgrp()函数没有参数,返回一个进程的进程组ID.
getpgid()函数,获取指定pid进程的进程组号(PGID).如果pid是0,表示获取当前进程的进程组号(PGID).(getpgid()函数获取进程组号PGID,除了需要调用者作为参数,其他并不需要,所以一般是选用getpgrp())
在System V version中,setpgrp()函数不需要任何参数,等价于setpgid(0,0);
在BSD version中,setpgrp()函数需要两个参数,库函数调用方式为setpgid(pid,pgid).
自从glibc 2.19版本以后,setpgrp()函数不再公开,所以应该使用setpgid()函数替代setpgrp()函数.
在BSD version中,getpgrp()函数需要一个参数,库函数调用方式为getpgid(pid).
自从glibc 2.19版本以后,getpgrp()函数不再公开,所以应该使用POSIX.1规定中的无参数getprgp()函数调用替代getpgid(pid)函数调用(如果目的是为了获取进程组号(PGID)).或者使用getpgid(pid).
按POSIX.1的标准,getprpg()函数总是执行成功,返回调用者的进程组号(PGID).
getpgid()函数和getpgrp()函数执行成功,返回一个进程组号的PGID,出错返回-1,并设置errno的值.
EINVAL pgid参数小于0.(setpgid(),setpgrp())
EPERM 权限不满足,无法调用修改.企图将一个进程添加到一个会话号不同的进程组,或者修改一个不同会话号的子进程组的进程组号(PGID),或者是讲一个进程组号(PGID)设置为会话首进程.(setpgid(),setpgrp())
ESRCH 对于getpgid(),找不到pid进程.对于setpgid(),pid不是当前进程,也不是其子进程.
POSIX.1-2001标准也规定了getpgid()和无参数的setpgrp().
一个参数的getpgrp()和两个参数的setpgrp() 是在4.2BSD规定的,而不是在POSIX.1.
如果进程组是会话的一员,则进程组的进程也是会话的一员.
一个会话可以拥有一个控制终端,会话有一个前台进程组,会话的其他进程组则为后台进程组.
在任何时候,如果在终端键入一个信号(比如终端信号),就会将该信号发送给前台进程组的所有进程.
只有前台进程组的进程才可以从终端读取数据;如果后台进程组的进程尝试从终端读取数据,进程组会发送一个SIGTTIN信号,中断该操作.
函数tcgetpgrp()和tcsetpgrp()用来获取或设置前台进程组的控制终端.
为了实现控制终端的任务,通常用函数setpgid()和getpgrp()在shell下创建一个进程组.
如果终端接口监测到调制解调器已经断开连接,则将挂断信号发送给控制终端进程(会话首进程).如果会话首进程存在,则中断信号也将被发送给每一个控制终端的前台进程组中的进程.
如果由于某进程退出导致该进程组成为孤儿进程组,该孤儿进程组中处于停止状态的进程将会先发送一个SIGCONT信号再发送SIGHUP信号.进程组中进程的父进程都是当前进程组中的进程,或者是其他会话中进程,这样的进程组称之为孤儿进程组.
setpgid()、getpgid()、setpgrp()和getpgrp()函数
NAME
setpgid()、getpgid()、setpgrp()和getpgrp()函数 - 设置或获取进程组ID.
SYNOPSIS
#include <unistd.h>int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); /* POSIX.1 version */
pid_t getpgrp(pid_t pid); /* BSD version */
int setpgrp(void); /* System V version */
int setpgrp(pid_t pid, pid_t pgid); /* BSD version */
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
getpgid():
_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
setpgrp() (POSIX.1):
_SVID_SOURCE || _XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.19: */ _BSD_SOURCE
setpgrp() (BSD), getpgrp() (BSD) [before glibc 2.19]:
_BSD_SOURCE &&
! (_POSIX_SOURCE || _POSIX_C_SOURCE || _XOPEN_SOURCE ||
_XOPEN_SOURCE_EXTENDED || _GNU_SOURCE || _SVID_SOURCE)
DESCRIPTION
在Linux系统上,这些接口都可以使用,用来设置或获取一个进程的进程组ID(PGID).按POSIX.1的规定,首选是:获取进程组ID(PGID),使用getpgid()函数,设置进程组ID(PGID),使用setpgid()函数.setpgid()函数将pid进程的进程组ID(PGID)设置为pgid.如果pid是0,则使用调用者的进程ID.如果pgid是0,则由pid指定的进程ID(PID)将用作进程组ID(PGID).如果使用setpgid()函数将某进程组的一个进程指定到另一个进程组,则要求两个进程组是属于同一个会话.在这种情况下,进程和进程组的会话(ID)相同,进程可以加入到由pgid指定的进程组中.
在POSIX.1标准中,getpgrp()函数没有参数,返回一个进程的进程组ID.
getpgid()函数,获取指定pid进程的进程组号(PGID).如果pid是0,表示获取当前进程的进程组号(PGID).(getpgid()函数获取进程组号PGID,除了需要调用者作为参数,其他并不需要,所以一般是选用getpgrp())
在System V version中,setpgrp()函数不需要任何参数,等价于setpgid(0,0);
在BSD version中,setpgrp()函数需要两个参数,库函数调用方式为setpgid(pid,pgid).
自从glibc 2.19版本以后,setpgrp()函数不再公开,所以应该使用setpgid()函数替代setpgrp()函数.
在BSD version中,getpgrp()函数需要一个参数,库函数调用方式为getpgid(pid).
自从glibc 2.19版本以后,getpgrp()函数不再公开,所以应该使用POSIX.1规定中的无参数getprgp()函数调用替代getpgid(pid)函数调用(如果目的是为了获取进程组号(PGID)).或者使用getpgid(pid).
RETURN VALUE
setpgid()和setpgrp()函数,成功返回0,失败返回-1,并设置errno的值.按POSIX.1的标准,getprpg()函数总是执行成功,返回调用者的进程组号(PGID).
getpgid()函数和getpgrp()函数执行成功,返回一个进程组号的PGID,出错返回-1,并设置errno的值.
ERRORS
EACCES 企图修改子进程的进程组号(PGID),但子进程已经调用了exec等系列函数的.EINVAL pgid参数小于0.(setpgid(),setpgrp())
EPERM 权限不满足,无法调用修改.企图将一个进程添加到一个会话号不同的进程组,或者修改一个不同会话号的子进程组的进程组号(PGID),或者是讲一个进程组号(PGID)设置为会话首进程.(setpgid(),setpgrp())
ESRCH 对于getpgid(),找不到pid进程.对于setpgid(),pid不是当前进程,也不是其子进程.
CONFORMING TO
setpgid()和无参数getpgrp()都遵守POSIX.1-2001标准.POSIX.1-2001标准也规定了getpgid()和无参数的setpgrp().
一个参数的getpgrp()和两个参数的setpgrp() 是在4.2BSD规定的,而不是在POSIX.1.
NOTES
通过fork()函数产生的子进程会继承它的父进程的进程组ID(PGID),进程组ID(PGID)靠execve()函数维护.如果进程组是会话的一员,则进程组的进程也是会话的一员.
一个会话可以拥有一个控制终端,会话有一个前台进程组,会话的其他进程组则为后台进程组.
在任何时候,如果在终端键入一个信号(比如终端信号),就会将该信号发送给前台进程组的所有进程.
只有前台进程组的进程才可以从终端读取数据;如果后台进程组的进程尝试从终端读取数据,进程组会发送一个SIGTTIN信号,中断该操作.
函数tcgetpgrp()和tcsetpgrp()用来获取或设置前台进程组的控制终端.
为了实现控制终端的任务,通常用函数setpgid()和getpgrp()在shell下创建一个进程组.
如果终端接口监测到调制解调器已经断开连接,则将挂断信号发送给控制终端进程(会话首进程).如果会话首进程存在,则中断信号也将被发送给每一个控制终端的前台进程组中的进程.
如果由于某进程退出导致该进程组成为孤儿进程组,该孤儿进程组中处于停止状态的进程将会先发送一个SIGCONT信号再发送SIGHUP信号.进程组中进程的父进程都是当前进程组中的进程,或者是其他会话中进程,这样的进程组称之为孤儿进程组.
END
笔者:个人能力有限,只是学习参考...读者若发现文中错误,敬请提出.
--
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------