linux多进程——进程组与会话、守护进程、信号通信

  一、进程组与会话

    进程组:是一个或多个进程的集合。可以调用 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、内核只会保存一个同类的信号,其他的都被丢掉了。

 

 

 

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值