信号的产生

1)终端按键产生信号(与终端交互的进程)

Ctrl + c  → 2) SIGINT(终止/中断)      "INT" ----Interrupt

Ctrl + z  → 20) SIGTSTP(暂停/停止)  "T" ----Terminal 终端  此时进程处于后台运行

Ctrl + \  → 3) SIGQUIT(退出)    

2)硬件异常产生信号

除0操作   → 8) SIGFPE (浮点数例外)    "F" -----float 浮点数。

非法访问内存  → 11) SIGSEGV (段错误)

总线错误  → 7) SIGBUS(内存未对齐)

3kill函数/命令产生信号

注意:kill函数或命令产生信号并不一定是要杀死进程,信号的含义是根据编号(或宏)来决定的,不是kill本身的含义。

kill命令向指定进程发送指定信号: kill –SIGKILL pid  // 终止该进程,向该进程发送9号信号   

kill函数向指定进程发送指定信号:

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid, int sig);

作用:向指定进程(pid)发送指定信号(sig),指定信号最好用宏表示,不用编号,因为在不同类型的操作系统中,信号的编号可能会不一样,用宏表示可以增强移植性。

返回值:成功0,失败-1(ID非法;信号非法;普通用户杀init进程等权级问题,即权限不够)。

pid > 0:发送信号给指定的进程。

pid = 0:发送信号给与调用kill函数进程属于同一进程组的所有进程(包括本身)。

pid < 0:取|pid|发给对应进程组。

pid = -1:发送给进程有权限发送的系统中所有进程(包括本身)。

进程组:每个进程都属于一个进程组,进程组是一个或多个进程集合,他们相互关联,共同完成一个实体任务,每个进程组都有一个进程组长,默认进程组ID与进程组长ID相同。

权限保护:super用户(root)可以发送信号给任意用户,普通用户是不能向系统用户发送信号的。同样,普通用户也不能向其他普通用户发送信号,终止其进程。 只能向自己创建的进程发送信号。普通用户基本规则是:发送者实际或有效用户ID == 接收者实际或有效用户ID

4raiseabort函数(系统调用产生,包括上面的kill函数)

raise函数:给当前进程发送指定信号(自己给自己发),则有:raise(signo) == kill(getpid(), signo);

#include <signal.h>

int raise(int sig);   成功:0,失败非0值

 

abort 函数:给自己发送异常终止信号 6) SIGABRT 信号,终止并产生core文件

#include <stdlib.h>

void abort(void);

5alarmsetitimer函数(软件条件产生)

设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送14)SIGALRM信号。进程收到该信号,默认动作终止(结束进程)。每个进程都有且只有唯一个定时器。

#include <unistd.h>

unsigned int alarm(unsigned int seconds);成功:返回旧闹钟剩余的秒数,即该进程上一次调用alarm函数后还剩下的秒数;或者返回0(第一次调用alarm函数的时候)。无失败。

注意:alarm(0)表示取消闹钟,不是说0秒后终止进程,是取消闹钟。另外:定时与进程状态无关(自然时间),就绪、运行、挂起(阻塞、暂停)、终止、僵尸等,无论进程处于何种状态,alarm都计时。

例:alarm(5) → 3sec → alarm(4) → 5sec → alarm(5) →0sec→ alarm(0)

alarm(5)返回0   alarm(4)返回2    alarm(5)返回0   紧随着马上的alarm(0)返回5,并且取消闹钟。

time命令。 time ./zsx 查看程序zsx执行的时间,时间由三部分组成:程序在进程系统空间运行的时间+用户空间的时间+等待的时间(等待CPU、各种硬件资源等)=程序实际执行的时间。程序运行的瓶颈在于IO,优化程序,首选优化IO。

 

//练习:编写程序,测试你使用的计算机1秒钟能数多少个数。

#include <stdio.h>
#include <unistd.h>

int main(void)
{
        int i;
        alarm(1);

        for(i = 0; ; i++)
                printf("%d\n", i);

        return 0;
}

#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

作用:类似alarm函数,有四点不一样:1.setitimer函数对时间的计算方式有三种,用which参数指定,而alarm函数只有一种(自然时间);2. setitimer函数可以进行周期定时,即等待it_value时间后执行某一动作(收到信号),以后每隔it_interval时间再执行这一动作。而alarm函数只能实现等待it_value时间后执行某一动作(收到信号);3. setitimer函数可以精确到us级别,即其时间为tv_sec与tv_usec之和;4.返回值不一样。

返回值:成功0;失败-1,设置errno

参数which指定定时方式:1.自然定时:ITIMER_REAL → 14SIGALRM 计算自然时间;2.虚拟空间计时(用户空间):ITIMER_VIRTUAL → 26SIGVTALRM      只计算进程占用cpu的时间;3.运行时计时(用户+内核):ITIMER_PROF → 27SIGPROF  计算占用cpu及执行系统调用的时间(即相对于自然时间,不包括等待时间)。

参数new_value为传入参数,指定计时的大小,与alarm的参数作用一样;

参数old_value为传出参数,指定就旧闹钟剩余的秒数,作用类似alarm的返回值;结构体详细描述如下:

struct itimerval {

struct timeval it_interval; /* next value */   下一次定时的值(间隔时间)

    struct timeval it_value;    /* current value */  当前定时的值

};     // it_intervalit_value设置为0表示清零操作,即取消定时。

struct timeval {

time_t       tv_sec;         /* seconds */    s

    suseconds_t   tv_usec;        /* microseconds */  us

};

注意:每个进程都有且只有唯一个定时器。setitimer函数和alarm函数共用同一个定时器(闹钟)。

 

//练习: 使用setitimer函数实现alarm函数,重复计算机1秒数数程序。   

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

unsigned int my_alarm(unsigned int sec)    //实现alarm函数
{
        struct itimerval it, oldit;
        int ret;

        it.it_value.tv_sec = sec;
        it.it_value.tv_usec = 0;
        it.it_interval.tv_sec = 0;
        it.it_interval.tv_usec = 0;

        ret = setitimer(ITIMER_REAL, &it, &oldit);
        if (ret == -1) {
            perror("setitimer");
            exit(1);
        }
        return oldit.it_value.tv_sec;
}

int main(void)
{
        int i;
        my_alarm(1);  //alarm(sec);

        for(i = 0; ; i++)
                printf("%d\n", i);

        return 0;
}

//拓展练习:测试it_intervalit_value这两个参数的作用。

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

void myfunc(int signo)
{
    printf("hello world\n");
}

int main(void)
{
        struct itimerval it, oldit;
        signal(SIGALRM, myfunc);   //注册SIGALRM信号的捕捉用户处理函数,signal函数用于对信号进行注册,真正捕捉该信号的是内核,内核捕捉该信号后就会去调用signal注册时对应的用户处理函数。    信号捕捉函数signal是一个典型的回调函数

        it.it_value.tv_sec = 5;
        it.it_value.tv_usec = 0;

        it.it_interval.tv_sec = 3;
        it.it_interval.tv_usec = 0;

        if(setitimer(ITIMER_REAL, &it, &oldit) == -1){
                perror("setitimer error");
                return -1;
        }

        while(1);

        return 0;
}

[root@localhost 01_signal_test]# ./setitimer1

hello world    //5s

hello world    //3s

hello world    //3s

hello world    //3s

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值