寒假学习 第18、19天 (linux 高级编程) 笔记 总结
接着上上次
一、信号
3.信号的应用(实现多任务)
使用定时器实现多任务
例子:同时显示随机数与时间
#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;
}
sleep与pause函数被信号影响后,sleep不在继续睡眠, pause不在暂停。
例子:显示随机数,并且用空格控制暂停
#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); 向自己发送一个信号
4.信号的可靠与不可靠以及信号的含义
引出的例子:
#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 可靠信号(用户信号)
5.信号的操作
(1). 信号屏蔽
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!”不会输出
(2). 信号屏蔽的切换
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;
}
这样发出SIGUSR1 信号也不能进行下去。因为SIGUSR1加入了屏蔽的范畴
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信号
这样就可以把信号控制在每个局部,使信号可控(如果不这样做信号在那里都有可能发生,导致程序不可控)
(3). 查询被屏蔽的信号
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!”