摘要:本文主要介紹進程的基本屬性,基本屬性包括:進程ID、父進程ID、進程組ID、會話和控制終端.
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
函數說明:
每個進程都有一個非負整型表示的唯一進程ID(PID).好比如我們的身份證一樣,每個人的身份證號是唯一的.因爲進程ID標示符總是唯一的,常將其用來做其他標示符的一部分以保證其唯一性,進程ID(PID)是無法在用戶層修改的.
在Linux系統中,PID爲0 的進程通常是調度進程,常常被稱爲交換進程,也是第一個系統進程.第一個用戶進程是init進程,其PID爲1.
在應用編程中,調用getpid()函數可以獲得當前進程的PID,此函數沒有參數,如果執行成功返回當前進程的PID,失敗返回-1,出錯原因存儲於errno.
例子1:打印自己的進程ID(PID).
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
函數說明:
任何進程(除init進程)都是由另一個進程創建,該進程稱爲被創建進程的父進程,被創建的進程稱爲子進程,父進程ID無法在用戶層修改.父進程的進程ID即爲子進程的父進程ID(PPID).
用戶可以通過調用getppid()函數來獲得當前進程的父進程ID(PPID).此函數沒有參數,如果執行成功返回當前進程的父進程ID(PPID),失敗返回-1,出錯原因存儲於errno.
例子1:打印自己的父進程PPID.
#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 */
函數說明:
在Linux系統中,每個用戶都有用戶ID(UID)和用戶組ID(GUID).同樣,進程也擁有自己的進程ID(PID)和進程組ID(PGID). 進程組是一個或多個進程的集合;他們與同一作業相關聯.每個進程組都有唯一的進程組ID(PGID),進程組ID(PGID)可以在用戶層修改.比如,將某個進程添加到另一個進程組,就是使用setpgid()函數修改其進程組ID.
用戶可以通過調用getpgid()函數來獲得當前進程的進程組ID(PGID).若此參數爲0表示獲取當前進程的進程組ID,如果執行成功返回當前進程的進程組ID(PGID),失敗返回-1,出錯原因存儲於errno. 建議使用POSIX.1規定中的無參數getprgp()函數替代getpgid(pid)函數.
進程組ID(PGID)也可以通過函數getpgrp()獲得.通過fork()函數產生的子進程會繼承它的父進程的進程組ID(PGID).
每個進程組都可以有一個組長進程,組長進程的進程組ID等於其進程ID.但組長進程可以先退出,即只要在某個進程組中有一個進程存在,則該進程組就存在,與其組長進程是否存在無關.進程組的最後進程可以退出或轉移到其他組.
可以將某個進程加入到某個進程組中,調用系統函數setpgid().其第一個參數爲欲修改進程組ID(PGID)的進程ID(PID),第二參數爲新的進程組ID(PGID),如果這兩個參數相等,則由pid指定的進程變爲該進程組組長;如果pid爲0,則使用調用者的進程ID(即修改當前進程的進程組ID(PGID爲指定的pgid));如果pgid是0,則由pid指定的進程ID(PID),用做進程組ID(PGID)(即:pid所指進程作爲進程組的組長進程).
一個進程只能爲自己或子進程設置進程組ID(PGID),如果在它的子進程中調用了exec()等系列函數,就不再能改變該子進程的進程組ID(PGID).
#include <unistd.h>
pid_t getsid(pid_t pid);
pid_t setsid(void);
函數說明:
會話是一個或多個進程組的集合.系統調用函數getsid()用來獲取某個進程的會話ID(SID).
如果pid是0,返回調用進程的會話SID,一般說來,改制等於進程組ID(PGID).如果pid並不屬於調用者所在的會話,則調用者就無法獲取SID.
某個進程的會話ID也是可以修改的,調用函數setsid()用來創建一個新的會話.
如果調用進程已經是一個進程組的組長,則此函數返回錯誤.如果不是,則返回一個新的會話.
(1)該進程變成新會話首進程,會話首進程是創建該會話的進程,此時,該進程是新會話唯一的進程.
(2)該進程成爲一個新的進程組的組長進程.新的進程組ID(PGID)是該調用進程的PID.
(3)該進程沒有控制終端.如果在調用setsid()之前該進程就有一個控制終端,那麼這種聯繫也會中斷.
#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
函數說明:
會話和進程組的關係:
(1)一個會話可以有一個控制終端,建立於控制終端相連接的會話首進程被稱爲控制進程.
(2)一個會話中的幾個進程組可被分爲一個前臺進程組和幾個後臺進程組,如果一個會話有一個控制終端,則他有一個前臺進程組.
(3)無論何時鍵入終端的中斷鍵,都會將中斷信ID發送給前臺進程組的所有會話;無論何時鍵入終端的退出鍵,都會將退出信ID發送給前臺進程組的所有會話.
如果終端監測到調制解調器(或網絡)已經斷開連接,則將掛斷信ID發送給控制進程(會話首進程).
調用函數tcgetgrpt()獲取與打開的終端相關聯的前臺進程組的進程組ID.
調用函數tcsetgrpt()設置某個進程組是前臺進程還是後臺進程組.
如果進程有一個控制終端,則將前臺進程組ID設置爲pgrp,pgrp的值應該在同一會話中的一個進程組的ID,fd爲控制終端的文件描述符.
如果調用tcsetpgrp()函數的是會話中的後臺進程組的進程,則該進程不會阻塞,或者忽略SIGTTOU信號.信號SIGTTOU將會發送給該進程組的所有進程.
當fd是指向進程的控制終端,函數tcgetpgrp()返回終端的前臺進程組的進程組ID,該ID值是一個大於1且沒有使用的值.如果fd指向的不是進程的終端,則函數返回-1,並設置errno指示出錯.
圖2 顯示控制終端的進程組和會話
進程基本屬性
1.進程ID(PID)
函數定義:#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
函數說明:
每個進程都有一個非負整型表示的唯一進程ID(PID).好比如我們的身份證一樣,每個人的身份證號是唯一的.因爲進程ID標示符總是唯一的,常將其用來做其他標示符的一部分以保證其唯一性,進程ID(PID)是無法在用戶層修改的.
在Linux系統中,PID爲0 的進程通常是調度進程,常常被稱爲交換進程,也是第一個系統進程.第一個用戶進程是init進程,其PID爲1.
在應用編程中,調用getpid()函數可以獲得當前進程的PID,此函數沒有參數,如果執行成功返回當前進程的PID,失敗返回-1,出錯原因存儲於errno.
例子1:打印自己的進程ID(PID).
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid; //pid_t 其實是int
pid = getpid();
printf("the current program's pid is %d\n",pid);
while(1);
return 0;
}
運行後使用“ps u”命令查看對照一下.
2.父進程ID(PPID)
函數定義:#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
函數說明:
任何進程(除init進程)都是由另一個進程創建,該進程稱爲被創建進程的父進程,被創建的進程稱爲子進程,父進程ID無法在用戶層修改.父進程的進程ID即爲子進程的父進程ID(PPID).
用戶可以通過調用getppid()函數來獲得當前進程的父進程ID(PPID).此函數沒有參數,如果執行成功返回當前進程的父進程ID(PPID),失敗返回-1,出錯原因存儲於errno.
例子1:打印自己的父進程PPID.
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t ppid; //pid_t 其實是int
ppid = getppid();
printf("the current program's ppid is %d\n",ppid);
while(1);
return 0;
}
運行後使用“ps u”命令查看對照一下.
3.進程組ID(process group ID PGID)
函數定義:#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 */
函數說明:
在Linux系統中,每個用戶都有用戶ID(UID)和用戶組ID(GUID).同樣,進程也擁有自己的進程ID(PID)和進程組ID(PGID). 進程組是一個或多個進程的集合;他們與同一作業相關聯.每個進程組都有唯一的進程組ID(PGID),進程組ID(PGID)可以在用戶層修改.比如,將某個進程添加到另一個進程組,就是使用setpgid()函數修改其進程組ID.
用戶可以通過調用getpgid()函數來獲得當前進程的進程組ID(PGID).若此參數爲0表示獲取當前進程的進程組ID,如果執行成功返回當前進程的進程組ID(PGID),失敗返回-1,出錯原因存儲於errno. 建議使用POSIX.1規定中的無參數getprgp()函數替代getpgid(pid)函數.
進程組ID(PGID)也可以通過函數getpgrp()獲得.通過fork()函數產生的子進程會繼承它的父進程的進程組ID(PGID).
每個進程組都可以有一個組長進程,組長進程的進程組ID等於其進程ID.但組長進程可以先退出,即只要在某個進程組中有一個進程存在,則該進程組就存在,與其組長進程是否存在無關.進程組的最後進程可以退出或轉移到其他組.
可以將某個進程加入到某個進程組中,調用系統函數setpgid().其第一個參數爲欲修改進程組ID(PGID)的進程ID(PID),第二參數爲新的進程組ID(PGID),如果這兩個參數相等,則由pid指定的進程變爲該進程組組長;如果pid爲0,則使用調用者的進程ID(即修改當前進程的進程組ID(PGID爲指定的pgid));如果pgid是0,則由pid指定的進程ID(PID),用做進程組ID(PGID)(即:pid所指進程作爲進程組的組長進程).
一個進程只能爲自己或子進程設置進程組ID(PGID),如果在它的子進程中調用了exec()等系列函數,就不再能改變該子進程的進程組ID(PGID).
#include <unistd.h>
#include <stdio.h>
int main()
{
int i;
printf("\t pid \tppid \t pgid\n");
printf("parent:\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0));
for(i=0; i<2; i++)
{
if(fork()==0)
{
printf("child:\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0));
}
}
sleep(500);
return 0;
}
輸出:
4.會話(session)
函數定義:#include <unistd.h>
pid_t getsid(pid_t pid);
pid_t setsid(void);
函數說明:
會話是一個或多個進程組的集合.系統調用函數getsid()用來獲取某個進程的會話ID(SID).
如果pid是0,返回調用進程的會話SID,一般說來,改制等於進程組ID(PGID).如果pid並不屬於調用者所在的會話,則調用者就無法獲取SID.
某個進程的會話ID也是可以修改的,調用函數setsid()用來創建一個新的會話.
如果調用進程已經是一個進程組的組長,則此函數返回錯誤.如果不是,則返回一個新的會話.
(1)該進程變成新會話首進程,會話首進程是創建該會話的進程,此時,該進程是新會話唯一的進程.
(2)該進程成爲一個新的進程組的組長進程.新的進程組ID(PGID)是該調用進程的PID.
(3)該進程沒有控制終端.如果在調用setsid()之前該進程就有一個控制終端,那麼這種聯繫也會中斷.
圖1 進程組合會話的進程安排
5.控制終端(controlling terminal)
函數定義:#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
函數說明:
會話和進程組的關係:
(1)一個會話可以有一個控制終端,建立於控制終端相連接的會話首進程被稱爲控制進程.
(2)一個會話中的幾個進程組可被分爲一個前臺進程組和幾個後臺進程組,如果一個會話有一個控制終端,則他有一個前臺進程組.
(3)無論何時鍵入終端的中斷鍵,都會將中斷信ID發送給前臺進程組的所有會話;無論何時鍵入終端的退出鍵,都會將退出信ID發送給前臺進程組的所有會話.
如果終端監測到調制解調器(或網絡)已經斷開連接,則將掛斷信ID發送給控制進程(會話首進程).
調用函數tcgetgrpt()獲取與打開的終端相關聯的前臺進程組的進程組ID.
調用函數tcsetgrpt()設置某個進程組是前臺進程還是後臺進程組.
如果進程有一個控制終端,則將前臺進程組ID設置爲pgrp,pgrp的值應該在同一會話中的一個進程組的ID,fd爲控制終端的文件描述符.
如果調用tcsetpgrp()函數的是會話中的後臺進程組的進程,則該進程不會阻塞,或者忽略SIGTTOU信號.信號SIGTTOU將會發送給該進程組的所有進程.
當fd是指向進程的控制終端,函數tcgetpgrp()返回終端的前臺進程組的進程組ID,該ID值是一個大於1且沒有使用的值.如果fd指向的不是進程的終端,則函數返回-1,並設置errno指示出錯.
圖2 顯示控制終端的進程組和會話
筆者:個人能力有限,只是學習參考...讀者若發現文中錯誤,敬請提出.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙築高臺,靜下心來,慢慢地沉澱---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------