寒假学习 第18、19天 (linux 高级编程) 笔记 总结
接着上上次
例子:同时显示随机数与时间
#include <curses.h> #include <unistd.h> #include <time.h> #include <stdlib.h> #include <sys/time.h> #include <signal.h> WINDOW *wtime,*wnumb; void showtime(int s) { time_t t; struct tm *tt; time(&t); tt=localtime(&t); mvwprintw(wtime,1,1,"%02d:%02d:%02d",tt->tm_hour,tt->tm_min,tt->tm_sec); refresh(); wrefresh(wtime); wrefresh(wnumb); } int main(int argc, const char *argv[]) { initscr(); box(stdscr,0,0); curs_set(0); wtime=derwin(stdscr,3,10,0,COLS-10); wnumb=derwin(stdscr,3,9,(LINES-3)/2,(COLS-9)/2); box(wtime,0,0); box(wnumb,0,0); refresh(); wrefresh(wtime); wrefresh(wnumb); signal(SIGALRM,showtime); struct itimerval val={0}; val.it_interval.tv_sec=1; val.it_value.tv_sec=0; val.it_value.tv_usec=1; setitimer(ITIMER_REAL,&val,0); int n; int numb; while(1) { n = 7; numb=0; while(n--) { numb=numb*10+rand()%10; } mvwprintw(wnumb,1,1,"%07d",numb); usleep(10000); refresh(); wrefresh(wtime); wrefresh(wnumb); } getch(); endwin(); return 0; }
例子:显示随机数,并且用空格控制暂停
#include <curses.h> #include <unistd.h> #include <signal.h> WINDOW *wtime; int isstop=0; void handle(int s) { isstop^=1; } int main(int argc, const char *argv[]) { initscr(); box(stdscr,0,0); curs_set(0); noecho(); wtime=derwin(stdscr,3,9,(LINES-3)/2,(COLS-9)/2); box(wtime,0,0); refresh(); wrefresh(wtime); if(fork()) { signal(SIGUSR1,handle); while(1){ if(isstop==1){ pause(); //pause 会被信号终端,它是受信号控制 } int numb=0; int n=7; while(n--) { numb=numb*10+rand()%10; } mvwprintw(wtime,1,1,"%07d",numb); refresh(); wrefresh(wtime); usleep(100000); } }else{ while(1) { char key; key=getch(); if(key==' ') kill(getppid(),SIGUSR1); //getppid() 获取父进程的 pid } } endwin(); return 0; }
int raise(int sig); 等同于 kill(getpid(), sig); 向自己发送一个信号
引出的例子:
#include <stdio.h> #include <signal.h> void handle(int s) { printf("信号!\n"); } int main(int argc, const char *argv[]) { signal(SIGINT,handle); printf("%d\n",getpid()); while(1); return 0; }生成main1
#include <stdio.h> #include <signal.h> int main(int argc, const char *argv[]) { int n=5; while(n--) { kill(3973,SIGINT); } return 0; }
生成main2
当main2运行时,main1不会显示5个信号。
信号有丢失(信号压缩)
由于历史的缘故:信息有压缩的需求
提出了可靠信号(实时信号)与不可靠信号(非实时信号)
早期 1~31 信号,这些信号都是不可靠(这些信号基本上与系统有关)
SIGWINCH (28) 窗口大小发送改变时发送的信号
后期提出的信号 34~64 可靠信号(用户信号)
int sigprocmask(int how, // 操作方式 SIIG_BLOCK 设置屏蔽 SIG_UNBLOCK 解除屏蔽 SIG_SETMASK
const sigset_t *set, //信号集合
sigset_t *oldset);// 返回原来操作的信号集合。
步骤(1)声明信号集合
sigset_t sigs;
(2)加入屏蔽信号
一组信号集合维护函数
1. 信号集合 sigemptyset
2. 添加信号到集合 sigaddset
3. 从集合删除信号 sigdelset
4. 添加所有信号到集合 sigfillset
5. 判定信号是否在集合 sigismember
(3)屏蔽信号
(4)解除屏蔽
例子
#include <stdio.h> #include <signal.h> int main(int argc, const char *argv[]) { int i; int sum=0; sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs,SIGINT); sigprocmask(SIG_BLOCK,&sigs,0); for(i=0;i<10;++i){ sum+=i; sleep(1); } printf("sum=%d\n",sum); sigprocmask(SIG_UNBLOCK,&sigs,0); printf("over!\n"); return 0; }运行时,按下ctrl+C(SIGINT) 没效果,当解除屏蔽信号马上起效,如果按了ctrl+C “over!”不会输出
int sigsuspend(const sigset_t *mask);
sigsuspend是阻塞函数,对参数信号屏蔽,但是对参数没有指定的信号,但当没有屏蔽的信号处理函数调用完毕sigsuspend函数返回
例子:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int s) { printf("非屏蔽信号发生!\n"); } int main(int argc, const char *argv[]) { printf("pid:%d\n",getpid()); sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs,SIGINT); signal(SIGUSR1,handle); printf("屏蔽开始\n"); sigsuspend(&sigs); printf("屏蔽解除\n"); return 0; }
运行到 sigsuspend 程序阻塞,只有发出SIGUSR1 的信号 (kill -10 pid)才能继续进行
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int s) { printf("非屏蔽信号发生!\n"); } int main(int argc, const char *argv[]) { printf("pid:%d\n",getpid()); sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs,SIGINT); signal(SIGUSR1,handle); sigaddset(&sigs,SIGUSR1); //把SIGUSR1加入屏蔽集 printf("屏蔽开始\n"); sigsuspend(&sigs); printf("屏蔽解除\n"); return 0; }
sigsuspend返回条件:1.信号发生并且信号是非屏蔽信号
2.信号必须处理,而且处理函数返回后,sigsuspend在返回
sigsuspend主要用途:设置新的屏蔽信号,保存旧的屏蔽信号,而且但sigsuspend返回的时候自己会恢复旧的屏蔽信号
例子:
#include <stdio.h> #include <signal.h> void handle(int s) { printf("抽空处理SIGINT信号\n"); } int main(int argc, const char *argv[]) { int i; int sum=0; sigset_t sigs; sigset_t sigp; sigset_t sigq; signal(SIGINT,handle); sigemptyset(&sigs); sigemptyset(&sigp); sigemptyset(&sigq); sigaddset(&sigs,SIGINT); sigprocmask(SIG_BLOCK,&sigs,0); for(i=0;i<10;++i){ sum+=i; sigpending(&sigp); if(sigismember(&sigp,SIGINT)){ printf("SIGINT在排队!\n"); sigsuspend(&sigq); } sleep(1); } printf("sum=%d\n",sum); sigprocmask(SIG_UNBLOCK,&sigs,0); printf("over!\n"); return 0; }
不想背SIGINT信号所干扰,又想偷偷的处理一下SIGINT信号
这样就可以把信号控制在每个局部,使信号可控(如果不这样做信号在那里都有可能发生,导致程序不可控)
int sigpending(sigset_t *set);
例子:
#include <stdio.h> #include <signal.h> int main(int argc, const char *argv[]) { int i; int sum=0; sigset_t sigs; sigset_t sigp; sigemptyset(&sigs); sigaddset(&sigs,SIGINT); sigprocmask(SIG_BLOCK,&sigs,0); for(i=0;i<10;++i){ sum+=i; sigpending(&sigp); if(sigismember(&sigp,SIGINT)){ printf("SIGINT!\n"); } sleep(1); } printf("sum=%d\n",sum); sigprocmask(SIG_UNBLOCK,&sigs,0); printf("over!\n"); return 0; }当按下ctrl+C (SIGINT) 时就会显示 “SIGINT!”