9--Linux学习----信号

---------------------------------信号------------------------------------------

                             

   1. 信号的作用

     通知其他进程相应。进程之间一种通信机制

    信号处理函数:

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

小小案例(引出什么是信号)

//  signaldeal.c
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

void deal(int s)
{
	printf("信号发生!\n");
}

main()
{
	signal(SIGINT,deal);
	while(1)
	{
		printf("进程执行!\n");
		sleep(1);
	}
}


常见处理信号命令:

------------------------------------------------

$ kill  -s  信号  进程ID ----信号: 数字1-31  34-64

$kill -l  -- 查看所有信号

------------------------------------------------

案例: 使用程序发送信号

    int kill(pid pid, int s)

          进程ID:

                >0 :  发送信号到指定的进程

               =0 : 发送信号到该进程所在进程组的所有进程

               =-1 : 发送给所有进程,除init外

               <0 : 发送给指定的进程组。

  2.信号的发送 与 安装

      signal

      kill

  3.信号的应用

     3.1 延时器 timeout

         SIGALRM

         信号发出函数: alarm

         #include <unistd.h>

          unsigned int alarm(unsigned int seconds);

   说明: alarm函数在sec秒之后发送一个SIGALRM信号

     3.2 定时器(有周期性,反复发送)

      #include <sys/time.h>
       int setitimer(int which,  // 3种计时方式ITIMER_REAL(真实时间),ITIMER_VIRTUAL,ITIMER_PROF

                     const struct itimerval *new_value, // 定时器
                     struct itimerval *old_value); // 返回原来设置的定时器,如果为NULL,不返回


          struct itimerval {
               struct timeval it_interval; /* next value */  间隔时间
               struct timeval it_value;    /* current value */ 延时时间
           };

           struct timeval {
               time_t      tv_sec;         /* seconds */
               suseconds_t tv_usec;        /* microseconds */
           };

案例1: 指定时间执行

#include <stdio.h>
#include <signal.h>

void deal(int s)
{
	printf("起床!\n");
}

main()
{
	signal(SIGALRM,deal);
	alarm(5);
	while(1)
	{
	  // ....
	}
	
}

案例2: (5秒后,每隔1秒打印)

// alarm2.c
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>

void deal(int s)
{
   // printf("\7");
   fprintf( stdout, "\7" );
	printf("起床\n");
}

main()
{
	struct itimerval v = {0};
	signal(SIGALRM,deal);
	
	v.it_value.tv_sec = 5;    // 延时时间
	v.it_interval.tv_sec  = 1 ;///间隔时间
	setitimer(ITIMER_REAL,&v,0);
	
	while(1)
	{
		//...
	}
}

   信号的应用:

    系统与应用程序之间

    应用与应用程序之间

    父子进程之间

案例: 使用单进程 + 信号中断

    使用定时器信号(不是进程),实现多任务。


/// demo1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <curses.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>

WINDOW *wtime, *wnumb;
int num,i;


void showtime(int s)
{
	time_t tt;
	struct tm *t;
	if(s == SIGALRM)
	{
		tt = time(0);
		//time(&tt);
		t = localtime(&tt);
		mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);
		refresh();
		//wrefresh(wtime);
		//wrefresh(wnumb); 
	}
}

main()
{
    struct itimerval val;

	initscr();
	curs_set(0); /// 隐藏光标
	
	signal(SIGALRM,showtime);/// 绑定一个信号,让时间显示
	bzero(&val,sizeof(struct itimerval));
	val.it_value.tv_sec=0;  ///设置为立即显示延时时间,可以试试,这句不能少,不然滞后显示
	val.it_value.tv_usec = 1;// 间隔时间
	val.it_interval.tv_sec = 1;
	
	
	
	wnumb = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);  //高度3,宽度11
	wtime = derwin(stdscr,3,10,0,(COLS-10)/2);
	box(wnumb,0,0);  // 加上边框
	box(wtime,0,0);
	
	setitimer(ITIMER_REAL,&val,0);  //不可少,启动定时器
		
	while(1)
	{
		num = 0;
		for(i=0; i<7; ++i)
		{
			num = num*10 +rand()%10;
		}
		mvwprintw(wnumb,1,2,"%07d",num);
		refresh();
		wrefresh(wnumb);
		sleep(1);
		wrefresh(wtime);
		usleep(10000);
	}	
	endwin();
}




案例2 : 多进程 + 信号 的应用 

    实现父子进程之间的通信

    sleep  与 pause 函数被信号影响后,它们将不会继续执行。

    随机显示7位随机属,当按下空格后,随机数停止显示

// demo2.c 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <curses.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>

WINDOW *w;
int num;
int istop  =0;

void handle(int s)
{
	if(s == SIGUSR1)
	{
		if(istop == 0)
			 istop = 1;
		else
			 istop = 0;
	}
}

main()
{
	initscr();
	curs_set(0); // 隐藏光标
	noecho(); /// 禁止输入显示
	
	/// 创建子窗体
	w = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
	keypad(stdscr,TRUE); // z支持功能键
	keypad(w,TRUE);
	// 给窗体加边框
	box(w,0,0);
	refresh();
	wrefresh(w); 
	if( fork() ) /// 父进程
	{
	    signal(SIGUSR1,handle); // handle函数绑定到信号上
		while(1)
		{
			
			if(istop == 1)
			{
				pause();  /// 进程挂起
			}
			num = 0;
			num = rand()%10000000;
			mvwprintw(w,1,2,"%07d",num);
			refresh();
			wrefresh(w);
			usleep(100000);
		}
	}
	else  //子进程中处理按键 
	{
		while(1)
		{
		    int ch;
			ch = getch();
			if(ch == 32)  // 32指的是空格键
			{
				kill(getppid(),SIGUSR1);
			}
		}
	}
	endwin();
}



   4.信号的可靠与不可靠 

      信号有丢失现象。

      分为:可靠信号 与 不可靠信号

      早期: 信号1-31   31个信号,不可靠(与系统有关)

      后期: 信号34-64  可靠信号(用户有关)

  5.信号的操作

     信号导致的问题:

    1.信号的屏蔽

       #include <signal.h>

       int sigprocmask(int how,
  // 操作方式

          SIG_BLOCK ----把参数set中的信号添加到信号屏蔽字中

               SIG_SETMASK --- 把信号屏蔽字设置为参数set中的信号

               SIG_UNBLOCK ---  从信号屏蔽字中删除参数set中的信号

   const sigset_t *set,  // 操作信号的集合

   sigset_t *oldset);  // 返回原来操作的信号集合

   编程步骤:

    1.声明信号集合

      sigset_t  sigs;

    2.加入屏蔽信号

      一组信号集合维护函数

      2.1 清空集合  int sigemptyset(sigset_t *set);

      2.2 添加信号到集合  int sigaddset(sigset_t *set, int signum);

      2.3 从集合中删除信号 int sigdelset(sigset_t *set, int signum);

      2.4 添加所有信号到集合   int sigfillset(sigset_t *set); 

      2.5 判定信号是否在集合 int sigismember(const sigset_t *set, int signum);

    3.屏蔽信号

    4.解除屏蔽

案例: (花费10秒钟计算1-10之间的和,外界中断信号不会影响程序的执行)


// mask.c
#include <stdio.h>
#include <signal.h>

main()
{
	int sum = 0;
	int i;
	// 1
	sigset_t sigs;
	//2
	sigemptyset(&sigs); // 清空信号集合
	sigaddset(&sigs,SIGINT); // 添加SIGINT 这个信号到信号集合
	//3 屏蔽SIGINT(Ctrl+c) 这个信号
	sigprocmask(SIG_BLOCK,&sigs,0); 
	for(i=0; i<=10; ++i)
	{
		sum += i;
		sleep(1);
	}
	printf("sum = %d\n",sum);
	//4.
	sigprocmask(SIG_UNBLOCK,&sigs,0);// 从信号屏蔽子中删除参数set中的信号
	printf("Over!\n"); // 这个有可能被外界信号干扰
}

  2.信号屏蔽的切换

           int sigsuspend(const sigset_t *mask);-------------------目前还没有理解这个函数,


   sigsuspend 是阻塞函数,对参数信号屏蔽。

  3.查询被屏蔽的信号

          int sigpending(sigset_t *set);











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值