Linux高級 2019-5-18上午

1.孤兒進程

1.1 產生原因

  • 父進程先於子進程終止,就會產生孤兒進程,在某些開發環境下(需要子進程自己申請空間),孤兒進程的危害遠遠大於殭屍進程,因爲孤兒進程充滿了不確定性。

1.2 創建一個孤兒進程

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

int main()
{
	// 創建一個子進程
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent pid:%d\n", getpid());
	}
	else if(pid == 0)
	{
		while(1)
		{
			printf("Child pid:%d\n", getpid());
			sleep(1);
		}
	}

	return 0;
}

1.3 預防孤兒進程

  • 開發多進程模型時,要對進程數量、進程工作狀態、進程工作變化進行檢測,主要檢測父進程,使父進程的生命週期比大於子進程的生命週期。

1.4 init 核心進程將把所有失去父進程的子進程託管給圖形化進程

  • 注意:在ubuntu14.04下,所有失去父進程的子進程是由init進程託管的;在ubuntu16.04下,所有失去父進程的子進程將由圖形化進程託管。
  • 將init進程kill掉會導致關機或者重啓;將圖形化進程kill掉會註銷計算機。

2.進程間關係

2.1 從init進程到用戶程序進程的流程

  • 開機運行init進程,init進程fork許多子進程,其中一個使用exec族函數運行shell(終端)程序,在該進程中再次fork子進程,用來在終端上運行用戶自己生產的可執行文件;
  • init->fork->exec->shell->fork->exec->app->fork->子進程

2.2 進程組

  • 1.Linux下所有的進程都是強親緣關係,每一個進程都有進程組,進程組的概念非常最要,內核是通過進程組來有效管理多進程的。
  • 2.獲取進程組ID可以使用以下兩個函數:
    • pid_t getpid(pid_t pid):參數爲想要知道組id的進程id,返回值爲該進程的進程組id;
    • pid_t getpgrp(void):沒有參數,因此返回值爲調用該函數的進程所在的進程組id;
  • 3.進程組組長的標誌:pid == pgid

2.3 setpgid 函數

  • 1.該函數可以將進程轉移到其他組,或者創建一個新的進程組;
  • 2.子進程可以通過 setpgid 函數變爲新的進程組的組長(創建新的進程組);一個進程組的組長調用 setpgid 函數嘗試創建新的進程組沒有任何意義;
  • 3.int setpgid(pid_t pid, pid_t pgid):第一個參數是要設置的進程的id,第二個參數是要轉移到的進程組的組id;返回值爲0若轉移進程(創建進程組)成功,失敗則返回-1;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
	}
	else if(pid == 0)
	{
		printf("Child pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
		printf("\nSet pgid...\n");
		setpgid(getpid(), getpid());
		printf("Child pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
	}
	else
	{
		perror("fork call error");
		exit(1);
	}

	return 0;
}
  • 4.上述代碼運行結果

    • 子進程id不變,ppid不變,組id變爲了自己的pid。
  • 4.進程組組長使用 setpgid 函數可以將自己轉移到其他組,但不能創建一個新組;

2.4 每個新的進程都會參加一個會話,只要會話發起者終止,就會強制殺死所有參與者,所以想要進程不受會話限制,就要脫離現有會話(脫離控制終端),讓終端的存在與否與進程無關

  • 1.會話:會話是基於連接的;會話的源頭,就是用戶與系統之間連接的啓用;
  • 2.會話發起人標誌: pid == gid == sid ;
  • 3.想要發起新會話必須是進程組的組長;

2.5 setsid 函數

  • 1.任意進程調用該函數能完成兩項工作:
    • 1.1 是該進程創建一個新的進程組;
    • 1.2 是該進程變爲一個新會話的發起者(創建新會話);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
	}
	else if(pid == 0)
	{
		printf("Child pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
		printf("\nSet pgid...\n");
		setsid();
		printf("Child pid:%d\tppid:%d\tpgid:%d\t", getpid(), getppid(), getpgrp());
	}
	else
	{
		perror("fork call error");
		exit(1);
	}

	return 0;
}
  • 2.上述代碼運行結果(輸入 ps ajx 命令查看)
    • 子進程的pid與gid及sid(會話id)均相等。

2.6 守護進程(精靈進程daemon)

  • 1.生命週期較長(隨着系統持續),週期性執行某個固定任務持續在後臺運行,通常脫離終端獨立運行;
  • 2.守護進程是一種人爲的孤兒進程。

2.7 創建一個守護進程

  • 1.創建子進程,並終結父進程;
  • 2.子進程創建後創建新進程組並創建新會話;
  • 3.修改當前進程的工作目錄,這樣做的原因是:當刪除可執行文件後,無論可執行文件是否與其他文件進行交互都能繼續執行;
  • 4.改變當前進程的 umask 權限掩碼,目的是爲了能讓守護進程按照自己的功能創建文件;
  • 5.關閉無用的文件描述符,比如 STDIN_FILENO ;
  • 6.守護進程的核心工作(需要週期性執行的代碼);
  • 7.守護進程的推出處理;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	// 1.創建子進程
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		exit(1);
	}
	else if(pid == 0)
	{
		// 2.創建新的進程組和新的會話
		setsid();

		// 3.修改當前工作目錄
		chdir("/tmp/");

		// 4.改變當前進程的 umask 掩碼權限
		umask(0);

		// 5.關閉無用描述符
		close(STDIN_FILENO);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);

		// 6.守護進程核心工作
		int fd = open("daemon.log", O_RDWR|O_CREAT, 0664);
		time_t tm;
		char time_buf[100];
		while(1)
		{
			bzero(time_buf, sizeof(time_buf));
			tm = time();
			ctime_r(&tm, time_buf);
			write(fd, time_buf, sizeof(time_buf));
			sleep(3);
		}

		// 7.守護進程的推出處理
	}
	else
	{
		perror("fork error");
		exit(1);
	}

	return 0;
}
2.上述代碼是在 /tmp/ 文件夾下創鍵一個以 daemon.log 爲名的文件,並每個三秒向其中寫入當前的時間;當我們編譯完成後,運行 ./daemon 這個可執行文件,會發現終端沒有阻塞,而是直接重啓了新的一行,我們過上一會 cd 到 /tmp 下即可看到 daemon.log 文件,cat 查看以下即可看到記錄的時間;這個進程不會被當前終端關閉所終止,只能通過 kill 命令來終止
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章