進程組:是一個或多個進程的集合。可以調用 getpgid(0) 或 getpgrp() 來得到。進程組ID爲組長的進程ID。只要進程組中有一個進程存在,進程組就存在,與組長進程是否終止無關。調用 setpgid() 加入一個現有的進程組或創建一個新的進程組。
會話:一個或多個進程組的集合
可以用 setsid() 建立新會話,則該進程會變成新會話的首進程,同時成爲一個新進程組的組長進程,該進程沒有控制終端。
二、守護進程
守護進程的特點:沒有終端的限制,不受用戶、終端或其它的變化而受到影響。
創建守護進程的步驟:
出錯處理:因爲守護進程不依賴於終端,所以出錯信息是不能用 printf 滴,這..... 怎麼辦?莫怕,用 syslog() 就能搞定~
用系統日誌就要調用三個函數:openlog()、syslog()、closelog() 系統日誌存於 /var/log/messages
舉例:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<syslog.h>
- int main(){
- pid_t pid,s;
- int i;
- char *buff="Daemon Test!\n";
- if((pid = fork())<0){
- printf("fork error!\n");
- exit(1);
- }else if(pid> 0){
- exit(0);
- }
- //第一個參數爲在消息之前加入的字符串,第二個參數在每個消息中包含進程的ID,第三個參數指定程序發送的消息類型
- openlog("daemon_testlog",LOG_PID,LOG_DAEMON);
- if((s=setsid())<0){
- //第一個參數爲參數類型,第二個參數爲信息字符串
- syslog(LOG_ERR,"%s\n","setsid error!");
- }
- chdir("/");
- umask(0);
- for(i=0;i<getdtablesize();i++){ //關閉文件描述
- close(i);
- }
- while(1){
- syslog(LOG_INFO,"%s\n",buff);
- sleep(10);
- }
- closelog();
- return 0;
- }
三、信號
Linux對每種信號都制定了默認的操作。捕捉到信號可以採用默認的操作、可以忽略(SIGKILL 與 SIGSTOP除外)、也可以執行相應的自定義處理函數。
kill()、raise() 發信號。一些相關知識可以參考 Linux 信號通信
pause() 將進程掛起直到捕捉到信號爲止。
舉例1:
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- void my_func(int);
- int main() {
- printf("Wainting for signal: SIGINT/SIGQUIT...\n");
- signal(SIGINT,my_func);
- signal(SIGQUIT,my_func);
- pause();
- pause();
- exit(0);
- }
- void my_func(int sign_no){
- if (sign_no==SIGINT) {
- printf("I got CTRL+C!\n");
- } else if (sign_no==SIGQUIT) {
- printf("I got CTRL+\\!\n");
- }
- }
舉例2:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- int main(){
- pid_t pid;
- if((pid = fork())<0){
- printf("fork error!\n");
- exit(1);
- }else if(pid == 0){
- printf("Child process wait for singal....a\n");
- raise(SIGSTOP); //子進程向自己發送一個消息,線程停止
- printf("Child is dead\n"); //此句不會打出來,因爲進程直接被kill了
- }else{
- sleep(10);
- kill(pid,SIGKILL);
- wait(NULL);
- }
- return 0;
- }
alarm() 在進程中設置一個定時器,當時間到時,發出SIGALARM信號。一個進程只能有一個鬧鐘時間,新的將代替舊的。返回值爲新舊時間差值。
舉例:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- int main(){
- int ret=alarm(5);
- printf("alarm...%d\n",ret);
- sleep(3);
- ret=alarm(5);
- printf("alarm...%d\n",ret);
- pause();
- printf("never show\n");
- }
程序運行結果爲:alarm...0 alarm....2 。 2爲相差時間,程序收到SIGALARM默認執行的操作爲終止線程。
sigaction()函數:signal()的高級版~
例子:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- void my_func(int);
- int main(){
- struct sigaction sa,oldsa;
- printf("waiting for SIGINT/SIGQUIT......\n");
- sa.sa_handler=my_func; //設定處理函數
- sigemptyset(&sa.sa_mask); //清空信號集合
- sa.sa_flags=0; //對信號處理的選項一般設爲0
- sigaction(SIGINT,&sa,&oldsa); //oldsa爲保存舊的信號結構體
- sigaction(SIGQUIT,&sa,&oldsa);
- pause();
- pause();
- pause();
- pause();
- pause();
- pause();
- pause();
- }
- void my_func(int sig){
- if(sig == SIGINT){
- printf("Receive CTRL+C!\n");
- }
- else if(sig == SIGQUIT){
- printf("Receive CTRL+\\!\n");
- }else
- printf("Receive Signal!\n");
- }
信號集
通常就是這個步驟。清空信號集->添加信號->設置信號屏蔽->定義信號處理
舉例:
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- void my_func(int);
- int main() {
- struct sigaction sa1,sa2;
- sigset_t set;
- //清空
- if (sigemptyset(&set)<0) {
- perror("sigemptyset");
- exit(1);
- }
- //添加信號
- if (sigaddset(&set,SIGINT)<0) {
- perror("sigaddset SIGINT");
- exit(1);
- }
- if (sigaddset(&set,SIGQUIT)<0) {
- perror("sigaddset SIGQUIT");
- exit(1);
- }
- //設置信號
- if (sigismember(&set,SIGINT)) {
- sa1.sa_handler=my_func;
- sigemptyset(&sa1.sa_mask);
- sa1.sa_flags=0;
- sigaction(SIGINT,&sa1,NULL);
- }
- if (sigismember(&set,SIGQUIT)) {
- sa2.sa_handler=SIG_DFL;
- sigemptyset(&sa2.sa_mask);
- sa2.sa_flags=0;
- sigaction(SIGQUIT,&sa2,NULL);
- }
- //設置屏蔽字
- if (sigprocmask(SIG_BLOCK,&set,NULL)<0) {
- perror("sigprocmask");
- exit(1);
- } else {
- printf("Signal set is blocked!\n");
- }
- while(1){
- int c=getchar();
- if ((c=='u')||(c=='U'))
- break;
- }
- //解除屏蔽字
- if (sigprocmask(SIG_UNBLOCK,&set,NULL)<0) {
- perror("sigprocmask");
- exit(1);
- } else {
- printf("Signal set is unblocked!\n");
- }
- }
- void my_func(int sig){
- if(sig == SIGINT){
- printf("Receive CTRL+C!\n");
- }
- else if(sig == SIGQUIT){
- printf("Receive CTRL+\\!\n");
- }else
- printf("Receive signal!\n");
- }
[注] 1、解鎖的瞬間即調用處理函數。2、內核只會保存一個同類的信號,其他的都被丟掉了。