歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux 的進程組、會話、守護進程

Linux 的進程組、會話、守護進程

日期:2017/2/28 14:02:59   编辑:Linux教程

一、進程組ID

每個進程都屬於一個進程組。每個進程組有一個領頭進程。進程組是一個或多個進程的集合,通常它們與一組作業相關聯,可以接受來自同一終端的各種信號。每個進程組都有唯一的進程組ID(整數,也可以存放在pid_t類型中)。進程組由進程組ID來唯一標識。除了進程號外(PID)之外,進程組ID也是一個進程的必備屬性之一。

getpgrp: 獲得進程組 id, 即領頭進程的 pid
#include <unistd.h>
pid_t getpgrp(void);
//返回值;調用進程的進程組ID

#include<unistd.h>
pid_t getpgid(pid_t pid);
//若成功返回進程組id,失敗則返回-1.

每個進程組都有一個組長進程,組長進程的進程號等於進程組ID。組長進程可以創建一個進程組、創建該組中的進程。只要某個進程組中有一個進程存在,則該進程組就存在,與組長進程是否終止無關。從進程組創建開始到其中最後一個進程離開為止的時間區間成為進程組的生存期。進程組中最後一個進程可以終止或者轉移到另一個進程組中。
顯示子進程和父進程的組id

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
pid_t pid;

if ((pid=fork())<0) {
printf("fork error!");
}else if (pid==0) {
printf("The child process PID is %d.\n",getpid());
printf("The Group ID is %d.\n",getpgrp());
printf("The Group ID is %d.\n",getpgid(0));
printf("The Group ID is %d.\n",getpgid(getpid()));
exit(0);
}

sleep(3);
printf("The parent process PID is %d.\n",getpid());
printf("The Group ID is %d.\n",getpgrp());

return 0;
}

程序執行的結果:

二、會話
會話是一個或多個進程組的集合。例如:


#include<unistd.h>
pid_t setsid(void);
如果調用此函數的進程不是一個進程組的組長,則此函數就會創建一個新的會話,結果發生三件事:
1、該進程變成新會話的首進程。此時,該進程是新會話中唯一的進程。
2、該進程成為一個進程組的組長進程。新的進程組ID就是調用進程的ID。
3、該進程沒有控制終端。如果在調用setsid之前該進程有一個控制終端,那麼這種聯系也會斷掉。
如果該進程已經是一個進程組的組長,則此函數返回錯誤。為了保證不會發生這種事情,通常先調用fork,然後使其父進程終止,而子進程則繼續。因為子進程繼承了父進程的組ID,而其ID是新分配,兩者不可能相等,所以就保證了子進程不會是一個進程組長。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
pid_t pid;

if ((pid=fork())<0) {
printf("fork error!");
exit(1);
}else if (pid==0) {
printf("The child process PID is %d.\n",getpid());
printf("The Group ID of child is %d.\n",getpgid(0));
printf("The Session ID of child is %d.\n",getsid(0));
sleep(10);
setsid(); // 子進程非組長進程,故其成為新會話首進程,且成為組長進程。該進程組id即為會話進程
printf("Changed:\n");
printf("The child process PID is %d.\n",getpid());
printf("The Group ID of child is %d.\n",getpgid(0));
printf("The Session ID of child is %d.\n",getsid(0));
sleep(20);
exit(0);
}

程序執行的結果:

三、守護進程
在linux或者unix系統中在系統的引導的時候會開啟很多服務,這些服務就叫做守護進程。為了增加靈活性,root可以選擇系統開啟的模式,這些模式叫做運行級別,每一種運行級別以一定的方式配置系統。 守護進程是脫離於終端並且在後台運行的進程。守護進程脫離於終端是為了避免進程在執行過程中的信息在任何終端上顯示並且進程也不會被任何終端所產生的終端信息所打斷。

守護進程編程步驟
  1. 創建子進程,父進程退出
    •所有工作在子進程中進行
    •形式上脫離了控制終端
  2. 在子進程中創建新會話
    •setsid()函數
    •使子進程完全獨立出來,脫離控制
  3. 改變當前目錄為根目錄
    •chdir()函數
    •防止占用可卸載的文件系統
    •也可以換成其它路徑
  4. 重設文件權限掩碼
    •umask()函數
    •防止繼承的文件創建屏蔽字拒絕某些權限
    •增加守護進程靈活性
  5. 關閉文件描述符
    •繼承的打開文件不會用到,浪費系統資源,無法卸載
    •getdtablesize()
    •返回所在進程的文件描述符表的項數,即該進程打開的文件數目

該實例首先創建了一個守護進程,然後讓該守護進程每個10s在/tmp/dameon.log中寫入一句話。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>

#define MAXFILE 65535
int main()
{
pid_t pc;
int i,fd,len;
char *buf="This is a Dameon\n";
len =strlen(buf);
pc=fork();
if(pc<0){
printf("error fork\n");
exit(1);
}else if(pc>0)
exit(0);
setsid();
chdir("/");
umask(0);
for(i=0;i<MAXFILE;i++)
close(i);
while(1){
if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0){
perror("open");
exit(1);
}
write(fd, buf, len+1);
close(fd);
sleep(10);
}
}

我們可以看到程序每個10s就在對應的文件中寫入內容。

Copyright © Linux教程網 All Rights Reserved