美文网首页
进程通信之信号

进程通信之信号

作者: 二进制人类 | 来源:发表于2022-09-30 10:30 被阅读0次

相关API接口

发送信号给指定进程

#include <sys/types.h>
#include <signal.h>
/**
 * [kill 发送信号给指定的进程]
 * @param  pid [
 * pid有多种情况:
        1) pid > 0 表示给进程号为pid的进程发送信号;
        2) pid = 0 表示给调用进程的进程组中的每一个进程发送信号;
        3) pid = -1 表示给调用进程有权限发送信号的每一个进程发送信号;
        4) pid < -1 表示给进程组号为-pid的每一个进程发送信号;
 * ]
 * @param  sig [需要发送信号的编号,可以使用数字或者宏定义实现]
 * @return     [成功返回0,失败返回-1且修改errno的值]
 */
int kill(pid_t pid, int sig);
//等价于shell命令中 kill sig_num pid

实例

#include <sys/types.h>
#include <signal.h>

int main()
{
    int ret;
    ret = kill(16720, SIGSTOP);    /* 给16720进程发送SIGSTOP信号 */
    if (ret == -1)
    {
        perror("kill");
        return -1;
    }
    return 0;
}
#include <sys/types.h>
#include <signal.h>

/* 给具有亲缘关系的进程发送 */
int main()
{
    int ret;
    pid_t pid;
    pid = fork();
    if (pid == -1)
    {
        perror("fork");
        return -1;
    }
    else if (pid == 0)
    {
        while(1)
        {
            printf("child\n");
            sleep(1);
        }
        //kill(getppid(), SIGSTOP);    /* 子进程给父进程发送SIGSTOP信号 */
        exit(EXIT_SUCCESS);
    }
    sleep(5);
    ret = kill(pid, SIGINT);    /* 父进程给子进程发送信号SIGINT */
    if (ret == -1)
    {
        perror("kill");
        return -1;
    }
}

给调用进程发送信号

#include <signal.h>
/**
 * [raise 是给调用进程发送信号,等价于:kill(getpid(), sig)]
 * @param  sig [需要发送信号的编号,可以使用数字或者宏定义实现]
 * @return     [成功返回0,失败返回非0]
 */
int raise(int sig);

实例

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

int main()
{
    int ret;
    printf("嗨起来\n");
    sleep(2);
    printf("我嗨死了\n");
#if 0
    ret = kill(getpid(), SIGSTOP);
    if (ret == -1)
    {
        perror("kill");
        return -1;
    }
#else
    ret = raise(SIGSTOP);    /* 等价于ret = kill(getpid(), SIGSTOP); */
    if (ret != 0)
    {
        return -1;
    }
#endif
    while(1)
    {
        printf("***哈哈哈*** 又起来嗨了\n");
        sleep(1);
    }

    return 0;
}

给调用进程发送SIGABRT信号

#include <stdlib.h>
/*给调用进程发送SIGABRT信号,进程异常终止;功能等价于:ret = kill(getpid(), SIGABRT)*/
void abort(void);

实例

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

int main()
{
    int ret;
    printf("嗨嗨嗨嗨\n");
    sleep(2);
    printf("嗨死了\n");
#if 1
    ret = kill(getpid(), SIGABRT);
    if (ret == -1)
    {
        perror("kill");
        return -1;
    }
#else
    abort();/* 等价于:ret = kill(getpid(), SIGABRT); */
#endif

    while(1)
    {
        printf("***哈哈哈*** 起来继续嗨;\n");
        sleep(1);
    }

    return 0;
}

设定闹钟和定时器

#include <unistd.h>

/**
 * [alarm     
 * 1) 设置定时器(闹钟),当设置时间计数为零的时候,发送闹钟信号SIGALRM;
   2)在设置定时器(闹钟),如果已存在则取消原来的定时器,并设置新的定时器;
   ]
 * @param  seconds [秒数]
 * @return         [  
 *  1) 如果有设置定时器,则返回剩余秒数;
    2) 如果之前没有设置定时器,则成功返回0;
    ]
 */
unsigned int alarm(unsigned int seconds);

实例

#include <unistd.h>
#include <stdio.h>
int main()
{
    /* 设置定时器 */
    printf("%d\n", alarm(5));/* 第一次设置定时器,返回值为0 */
    sleep(3);
    printf("%d\n", alarm(5));/* 第二次设置定时器,返回上一次设置定时器的剩余时间2 */
    while(1)
    {
        printf("哇哇哇哇\n");
        sleep(1);
    }
    return 0;
}

设置定时器二

#include <sys/time.h>

/**
 * [getitimer description]
 * @param  which      [description]
 * @param  curr_value [description]
 * @return            [description]
 */
int getitimer(int which, struct itimerval *curr_value);
/**
 * [setitimer 设置定时器(闹钟)。 可代替alarm函数。精度微秒us,可以实现周期定时]
 * @param  which     [
 * which:指定定时方式
        1) 自然定时:ITIMER_REAL → 14)SIGALRM计算自然时间
        2) 虚拟空间计时(用户空间):ITIMER_VIRTUAL → 26)SIGVTALRM 只计算进程占用cpu的时间
        3) 运行时计时(用户 + 内核):ITIMER_PROF → 27)SIGPROF计算占用cpu及执行系统调用的时间
 * ]
 * @param  new_value [
 * struct itimerval, 负责设定timeout时间
        struct itimerval {
            struct timerval it_interval;     // 闹钟触发周期
            struct timerval it_value;         // 闹钟触发时间, 在设定之后的第一次触发需要的时间
        };
        struct timeval {
            long tv_sec; // 秒
            long tv_usec; // 微秒
        }
        itimerval.it_value: 设定第一次执行function所延迟的秒数
        itimerval.it_interval: 设定以后每几秒执行function
 * ]
 * @param  old_value [存放旧的timeout值,一般指定为NULL]
 * @return           [成功返回0,失败返回-1,且修改errno的值]
 */
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

实例

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

void myfunc(int sig)
{
    if (sig == SIGALRM)
        printf("timer out...\n");
}

int main()
{
    struct timeval it_value = {5, 0};
    struct timeval it_interval = {2, 0};
    struct itimerval newvalue = {it_interval, it_value};
    /* 注册信号处理函数 */
    signal(SIGALRM, myfunc);
    /* 设置定时器 */
    setitimer(ITIMER_REAL, &newvalue, NULL);
    while(1)
    {
        printf("test\n");
        sleep(1);
    }
    return 0;
}

注册信号

#include <signal.h>

typedef void (*sighandler_t)(int);
/**
 * [signal 注册信号]
 * @param  signum  [需要注册信号的编号]
 * @param  handler [
 * 处理方式:
        1) SIG_IGN    :忽略信号
        2) SIG_DFL    :系统默认信号处理方式
        3) 自定义信号处理函数,函数类型:参数是int返回值是void。
        ]
 * @return         [ 
 * 成功:第一次返回 NULL,下一次返回此信号上一次注册的信号处理函数的地址。如果需要使用此返回值,必须在前面先声明此函数指针的类型。
    失败:返回 SIG_ERR    ]
 */
sighandler_t signal(int signum, sighandler_t handler)

实例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void handler(int sig)
{
    printf("sig: %d\n", sig);
}
int main()
{
    /* 注册SIGINT信号的处理方式是忽略 */
    signal(SIGINT, SIG_IGN);
    signal(SIGSTOP, SIG_IGN);/* 无效的,因为SIGSTOP不能被忽略 */
    /* 注册SIGQUIT信号的处理方式是自定义信号处理函数 */
    signal(SIGQUIT, handler);
    while(1)
    {
        printf("哇哇哇哇\n");
        sleep(1);
    }
}

注册信号处理方式

#include <signal.h> 
/**
 * [sigaction 注册信号处理方式,指定信号signum的处理方式]
 * @param  signum [signum信号的编号,除了SIGKILL和SIGSTOP信号]
 * @param  act    [传递信号的新的处理方式,注册信号的处理方式]
 * @param  oldact [返回信号之前的处理方式,一般使用NULL。]
 * @return        [成功0 失败-1 修改errno值]
 */
int sigaction(int signum, const struct sigaction *act, struct sigaction*oldact);

 struct sigaction {
            void     (*sa_handler)(int);        //旧版本的信号处理函数指针
            void     (*sa_sigaction)(int, siginfo_t *, void *);    //新版本的信号处理函数指针
            sigset_t   sa_mask;    //信号阻塞集
            int        sa_flags;    //信号处理的方式
            void     (*sa_restorer)(void);    //已弃用
      };   
/*
 在有些系统中 sa_handler 和  sa_sigaction 使用联合体实现
void     (*sa_handler)(int);        
    如果使用该版本的信号处理函数,则只能在信号处理函数中去实现信号处理的功能,所以不能做延时处理操作。
void     (*sa_sigaction)(int signum, siginfo_t *info, void *context);     
    signum:信号的编号。
    info:记录信号发送进程信息的结构体。
    context:可以赋给指向 ucontext_t 类型的一个对象的指针,以引用在传递信号时被中断的接收进程或线程的上下文。  
    功能:在信号处理函数中来响应信号,并将信息添加到进程或者线程的上下文中,然后由上下文去处理信号。此时对于由耗时的信号处理也能够正常响应并处理 。
*/

实例

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

void my_sa_sigaction(int signum, siginfo_t *info, void *context)
{
    printf("signum = %d\n", signum);
}

int main()
{
    struct sigaction act;
    act.sa_sigaction = my_sa_sigaction;
    //act.sa_handler = SIG_IGN;
    sigaction(SIGQUIT, &act, NULL);
    while(1) {
        sleep(1);
        printf("sigaction\n");
    }
}
#include <signal.h>
int sigemptyset(sigset_t *set);            //将set集合置空
int sigfillset(sigset_t *set);            //将所有信号加入set集合
int sigaddset(sigset_t *set, int signum);   //将指定的signum信号加入到set集合 
int sigdelset(sigset_t *set, int signum);    //将指定signum信号从set集合删除
int sigismember(const sigset_t *set, int signum);    //判断指定signum信号是否存在set集合中

实例

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

int main()
{
    int i;
    int ret;
    /* 定义信号集合 */
    sigset_t set;

    printf("%d\n", sizeof(sigset_t));

    /* 清空信号set集合 */
    ret = sigemptyset(&set);
    if (ret == -1)
    {
        perror("sigemptyset");
        return -1;
    }

    /* 将所有信号添加到集合中 */
    ret = sigfillset(&set);
    if (ret == -1)
    {
        perror("sigfillset");
        return -1;
    }

    /* 从信号集合set中删除信号 */
    ret = sigdelset(&set, 5);
    if (ret == -1)
    {
        perror("sigdelset");
        return -1;
    }

    ret = sigdelset(&set, 15);
    if (ret == -1)
    {
        perror("sigdelset");
        return -1;
    }

    /* 向信号集合set中添加信号15 */
    ret = sigaddset(&set, 15);
    if (ret == -1)
    {
        perror("sigaddset");
        return -1;
    }

    /* 判断信号signum是否存在于集合set中 */
    for (i = 1; i <= 64; i++)
    {
        ret = sigismember(&set, i);
        if (ret == -1)
        {
            perror("sigismember");
            return -1;
        }
        else if (ret == 0)
        {
            printf("%d not is member\n", i);
        }
        else
        {
            printf("%d is member\n", i);
        }
    }
}

设置阻塞集

#include <signal.h>
/**
 * [sigprocmask 设置阻塞集]
 * @param  how    [
 *   SIG_BLOCK:向信号阻塞集合中添加 set 信号集,新的信号掩码是set和旧信号掩码的并集。
        相当于 mask = mask|set。
    SIG_UNBLOCK:从信号阻塞集合中删除 set 信号集,从当前信号掩码中去除 set 中的信号。
        相当于 mask = mask & ~ set。
    SIG_SETMASK:将信号阻塞集合设为 set 信号集,
        相当于原来信号阻塞集的内容清空,然后按照 set 中的信号重新设置信号阻塞集。
        相当于mask = set。
 * ]
 * @param  set    [set要操作的信号集地址。
        若 set 为 NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到 oldset 中。]
 * @param  oldset [oldset保存原先信号阻塞集地址]
 * @return        [成功:0,失败:-1,失败时错误代码只可能是 EINVAL,表示参数 how 不合法]
 */
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

实例

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

int main()
{
    int i;
    int ret;
    /* 定义信号集合 */
    sigset_t set;

    /* 清空信号set集合 */
    ret = sigemptyset(&set);
    if (ret == -1)
    {
        perror("sigemptyset");
        return -1;
    }

    /* 向信号集合set中添加信号SIGINT */
    ret = sigaddset(&set, SIGINT);
    if (ret == -1)
    {
        perror("sigdelset");
        return -1;
    }

    /* 设置阻塞集 */
    ret = sigprocmask(SIG_BLOCK, &set, NULL);
    if (ret == -1)
    {
        perror("sigprocmask");
        return -1;
    }

    while(1)
    {
        printf("sigprocmask\n");
        sleep(1);
    }
}

获取未决信号集合

#include <signal.h>
/**
 * [sigpending 获取未决信号集合]
 * @param  set [存储集合数据的地址]
 * @return     [成功返回0,失败返回-1修改errno的值]
 */
int sigpending(sigset_t *set);

相关文章

  • 进程通信之信号

    相关API接口 发送信号给指定进程 实例 给调用进程发送信号 实例 给调用进程发送SIGABRT信号 实例 设定闹...

  • 进程间通信(4)-信号

    一、信号 1、信号通信 信号通信,其实就是内核向用户空间进程发送信号。 只有内核才能发信号,用户空间进程不能发送信...

  • 用信号 (Signals) 实现进程间通信

    先备知识:进程通信之信号(Signals) 在这篇文章中,子进程和父进程之间的通信使用的是 kill() 和 si...

  • 进程间通信

    1.信号 信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程...

  • 进程通信之信号 (Signals)

    先备知识:fork()系统调用、wait()系统调用 信号是软件生成的中断,比如用户按下 Ctrl-C 或一个进程...

  • 第二章 进程通信、线程

    进程通信:进程通信是指进程之间的信息交换。 一、低级通信——进程之间的互斥和同步 信号量机制是有效的同步工具,但...

  • Android跨进程通信之AIDL(四)

    目录 Android跨进程通信之小例子(一)Android跨进程通信之非AIDL(二)Android跨进程通信之P...

  • Android跨进程通信之Proxy与Stub(三)

    目录 Android跨进程通信之小例子(一)Android跨进程通信之非AIDL(二)Android跨进程通信之P...

  • Android跨进程通信之非AIDL(二)

    目录 Android跨进程通信之小例子(一)Android跨进程通信之非AIDL(二)Android跨进程通信之P...

  • Android跨进程通信之小例子(一)

    目录 Android跨进程通信之小例子(一)Android跨进程通信之非AIDL(二)Android跨进程通信之P...

网友评论

      本文标题:进程通信之信号

      本文链接:https://www.haomeiwen.com/subject/rbcdartx.html