Linux技术-信号

Linux技术-信号

目的

  • 熟练使用kill命令管理进程。
  • 熟练掌握与信号相关的操作,包括阻塞信号、捕获信号,以及实现这些操作的接口。
  • 掌握解决信号机制中出现的时序竞态问题的方法。
  • 掌握通过信号机制回收多个子进程的方法。
    内容
  • 练习使用kill命令管理进程

①使用vi编辑程序,该程序可启动一个父进程和5个子进程,且父子进程都一直处于运行态。
②执行上述程序,使用kill命令对该程序创建的进程执行挂起、终止等操作。
③使用kill命令对该程序创建的整个进程组中的进程进行操作。

  • 屏蔽指定信号,实现信号阻塞

①编写程序,在程序中通过设置进程的信号集,屏蔽3号信号SIGQIUT,并在循环中不断
打印信号集中信号的状态。
②编写程序,在程序中通过signal()函数屏蔽3号信号SIGQIUT。

  • 捕获指定信号,执行自定义的信号处理函数

①编写程序,在程序中通过signal()函数捕获7号信号SIGBUS,若成功捕获,
则打印“catch SIGBUS”。
②编写程序,在程序中通过sigaction()函数捕获7号信号SIGBUS,若成功捕获,
则打印“catch SIGBUS”。
③编写程序,实现父子间进程同步,要求子进程等待父进程执行完毕后再结束运行。

  • 使用sigsuspend()函数解决时序竞态问题

编写程序,在程序中实现sleep()函数的功能,并通过自定义的sleep()函数使
进程沉睡一定时间,沉睡结束后打印“x seconds passed\n”。

  • 使用SIGCHLD信号实现多个子进程的回收

编写程序,在程序中创建多个子进程,使父进程利用信号机制,非阻塞地回收所
有子进程。

1、kill命令
使用vi编辑程序,在程序中创建多个子进程,并保证程序启动后创建的
父子进程能一直运行。

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <unistd.h>
 4	#include <pthread.h>
 5	int main()
 6	{
 7	    pid_t pid;
 8	    int i;
 9	    for(i=0;i<5;i++)
 10	    {   
 11	        if((pid=fork())==0)
 12	            break;
 13	    }   
 14	    if(pid<0){
 15	        perror("fork error.\n");
 16	        exit(0);
 17	    }   
 18	    else if(pid==0){        //child
 19	        while(1){}
 20	    }   
 21	    else if(pid>0){
 22	        while(1){}
 23	    }   
 24	    return 0;
 25	}

编译程序test_kill.c并执行,在终端通过kill命令对其启动的进程进行操作。

gcc test_kill.c –o test_kill ——编译程序
./test_kill & ——在后台执行
ps ao stat,pid,pgrp,command | grep ./test_kill
——查看test_kill启动的进程,依次打印状态、pid、进程组id和
启动进程的命令,打印结果如下:
在这里插入图片描述
使用“ps ao stat,pid,pgrp,command | grep ./test_kill”命令,打印结果如下:
在这里插入图片描述
kill -1 3912 ——发送1号信号到3912
kill -2 3913 ——发送2号信号到3913
kill -19 3914 ——发送19号信号到3914
使用“ps ao stat,pid,pgrp,command | grep ./test_kill”命令,打印结果如下:
在这里插入图片描述
kill -19 -3911
发送信号到进程组3911,此时使用“ps ao stat,pid,pgrp,command | grep ./test_kill”
命令,打印结果如下:
在这里插入图片描述
kill -9 -3911
——发送信号到进程组3911,此时使用“ps ao stat,pid,pgrp,command | grep ./test_kill”
命令,打印结果如下:
在这里插入图片描述
2、 屏蔽指定信号,实现信号阻塞
1 编写程序,在程序中通过设置进程的信号集,屏蔽3号信号SIGQUIT,
并在循环中不断打印信号集中信号的状态。
预备知识: sigemptyset()、sigfillset()、sigaddset()、sigdelset()、sigismember()。

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <signal.h>
 4	#include <unistd.h>
 5	void printset(sigset_t *ped)
 6	{
 7	    int i;
 8	    for(i=1;i<32;i++)
 9	    {   
 10	        if((sigismember(ped,i)==1))
 11	            putchar('1');
 12	        else
 13	            putchar('0');
 14	    }   
 15	    printf("\n");
 16	}
 17	int main()
 18	{
 19	    sigset_t set,oldset,ped;
 20	    sigemptyset(&set);
 21	    sigaddset(&set,SIGQUIT);
 22	    sigprocmask(SIG_BLOCK,&set,&oldset);
 23	    while(1){
 24	        sigpending(&ped);
 25	        printset(&ped);
 26	        sleep(1);
 27	    }
 28	    return 0;
 29	}

编译程序并执行,通过快捷键组合Ctrl+\发送3号信号到进程,程序的执行结果如下:
在这里插入图片描述
Ctril+C才能终止程序。
② 编写程序,在程序中通过signal()函数屏蔽3号信号SIGQUIT。
通过signal()函数实现信号屏蔽
预备知识:signal()函数
捕获指定信号,执行自定义的信号处理函数
``写程序,在程序中通过signal()函数捕获7号信号SIGBUS,若成功捕获,则打印“catch SIGBUS”。

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <signal.h>
 4	#include <unistd.h>
 5	void func(int signo)
 6	{
 7	    if(signo==SIGBUS)
 8	        printf("catch signal SIGBUS\n");
 9	}
 10	int main()
 11	{
 12	    signal(SIGBUS,func);
 13	    while(1)
 14	    {
 15	        printf("hello itlanmao\n");
 16	        sleep(2);
 17	    }
 18	    return 0;
 19	}

编写程序,在程序中通过sigaction()函数捕获2号信号SIGINT,若成功捕获
,则打印“catch SIGINT”。

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <signal.h>
 4	#include <unistd.h>
 5	
 6	void func(int signo)
 7	{
 8		if(signo==SIGBUS)
 9		{
 10			printf("catch signal SIGBUS\n");
 11		}
 12	}
 13	int main()
 14	{
 15		struct sigaction act,oldact;
 16		act.sa_handler=func;
 17		sigemptyset(&act.sa_mask);
 18		sigaddset(&act.sa_mask,SIGBUS);
 19		act.sa_flags=0;
 20		sigaction(SIGBUS,&act,&oldact);
 21		while(1)
 22		{
 23			printf("hello itlanmao\n");
 24			sleep(2);
 25		}
 26		return 0;
 27	}

编写程序,实现父子间进程同步,要求父进程中使用循环打印3次提示信息,
子进程等待父进程中的提示信息打印完毕后再结束运行。
预备知识:signal()函数、kill()函数

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <signal.h>
 4	#include <unistd.h>
 5	#include <sys/wait.h>
 6	int k1; 
 7	void func1(int signo)
 8	{
 9	    if(signo==SIGUSR2)
 10	        k1=0;
 11	}
 12	int main()
 13	{
 14	    int k,p1;
 15	    while((p1=fork())==-1);
 16	    if(p1>0)
 17	    {   
 18	        for(k=1;k<4;k++)
 19	        {
 20	            printf("parent:pid = %d\n",getpid());
 21	            sleep(1);
 22	        }
 23	        kill(p1,12);
 24	        wait(0);
 25	        printf("OK!\n");
 26	        exit(0);
 27	    }
 28	    else
 29	    {
 30	        signal(12,func1);
 31	        k1=1;
 32	        while(k1==1)
 33	        {
 34	            printf("I'm child\n");
 35	            sleep(1);
 36	        }
 37	        printf("Child exited!\n");
 38	        exit(0);
 39	    }
 40	    return 0;
 41	}

使用sigsuspend()函数解决时序竞态问题
编写程序,在程序中实现sleep()函数的功能,并通过自定义的sleep()函数使进程沉睡一定时间,
沉睡结束后打印“x seconds passed\n”。
预备知识:alarm()函数、sigsuspend()函数

 1	#include <stdio.h>
 2	#include <signal.h>
 3	#include <stdio.h>
 4	#include <unistd.h>
 5	
 6	void sig_alrm(int signo)
 7	{
 8	    if (signo == SIGALRM)
 9	        printf("sleep...\n");
 10	}
 11	unsigned int mysleep(unsigned int seconds)
 12	{
 13	    struct sigaction newact, oldact;
 14	    sigset_t newmask, oldmask, suspmask;
 15	    unsigned int unslept;
 16	    newact.sa_handler = sig_alrm;
 17	    sigemptyset(&newact.sa_mask);
 18	    newact.sa_flags = 0;
 19	    sigaction(SIGALRM, &newact, &oldact);
 20	    sigemptyset(&newmask);
 21	    sigaddset(&newmask, SIGALRM);
 22	    sigprocmask(SIG_BLOCK, &newmask, &oldmask);
 23	    alarm(seconds);
 24	    suspmask = oldmask;
 25	    sigdelset(&suspmask, SIGALRM);
 26	    sigsuspend(&suspmask);          //挂起进程,等待信号递达
 27	    unslept = alarm(0);
 28	    sigaction(SIGALRM, &oldact, NULL);
 29	    sigprocmask(SIG_SETMASK, &oldmask, NULL);
 30	    return unslept;
 31	}
 32	int main()
 33	{
 34	    while (1){
 35	        mysleep(2);
 36	        printf("two seconds passed\n");
 37	    }
 38	    return 0;
 39	}

使用SIGCHLD信号实现多个子进程的回收
编写程序,在程序中创建多个子进程,使父进程利用信号机制,非阻塞地回收所有子进程。
预备知识:fork()、sigaction()函数

 1	#include <stdio.h>
 2	#include <stdlib.h>
 3	#include <unistd.h>
 4	#include <sys/wait.h>
 5	#include <signal.h>
 6	void sys_err(char *str)
 7	{
 8	    perror(str);
 9	    exit(1);
 10	}
 11	void do_sig_child(int signo)                //信号处理函数
 12	{
 13	    int status;
 14	    pid_t pid;
 15	    while ((pid = waitpid(0, &status, WNOHANG)) > 0) {//判断子进程状态
 16	        if (WIFEXITED(status))
 17	            printf("child %d exit %d\n", pid, WEXITSTATUS(status));
 18	        else if (WIFSIGNALED(status))
 19	            printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
 20	    }   
 21	}
 22	int main(void)
 23	{
 24	    pid_t pid;
 25	    int i;
 26	    for (i = 0; i < 5; i++) {
 27	        if ((pid = fork()) == 0)           //创建一个子进程
 28	            break;
 29	        else if (pid < 0)                   //容错处理
 30	            sys_err("fork");
 31	    }
 32	    if (pid == 0) {                         //子进程执行流程
 33	        int n = 1;
 34	        while (n--) {
 35	            printf("child ID %d\n", getpid());
 36	            sleep(1);
 37	        }
 38	        return i + 1;
 39	    }
 40	    else if (pid > 0) {                     //父进程执行流程
 41	        struct sigaction act;
 42	        struct sigaction act;
 43	        act.sa_handler = do_sig_child;
 44	        sigemptyset(&act.sa_mask);
 45	        act.sa_flags = 0;
 46	        sigaction(SIGCHLD, &act, NULL);     //注册捕获函数
 47	        while (1) {                         //保证父进程运行
 48	            sleep(1);
 49	        }
 50	    }
 51	    return 0;
 52	}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itlanmao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值