您的位置:首页 > 运维架构 > Linux

寒假学习 第18、19天 (linux 高级编程)

2014-02-08 00:13 387 查看
寒假学习 第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!”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: