进程间通讯
引入
概述
 
 
    分类
1.信号量
2.管道
3.消息队列
4.socket(套接字)
5.内存共享
信号
概述
信号是Linux进程间通信的最古老方式
特点
简单
不能携带大量信息
满足某个特设条件才发出。
完整的信号周期
信号的注册
信号的产生
信号的处理函数
信号的注销
注意:这里的信号的注册,产生,注销是信号的内部机制,不是信号的函数实现
信号的编号
 
 
       
 
       
 
       
 
       
 
       
 
      信号的产生
kill函数(他杀)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
    int pid = fork();
    if(pid == 0)
    {
        //进入子进程
        while(1)
        {
            printf("子进程%u在玩游戏\n",getpid());
            sleep(1);
        }
        _exit(-1);
    }
    else if(pid > 0)
    {
        //进入父进程
        printf("给你三秒钟去写作业\n");
        sleep(3);
        kill(pid,SIGKILL);
        wait(NULL);
        printf("%d被%d干掉了\n",pid,getpid());
    }
    return 0;
}

raise函数(自杀)
作用:给当前进程自己发指定信号,等价于kill(getpid(),sig),自杀
语法:
所需头:
#include <signal.h>
函数:
int raise(int sig);
参数:
sig:信号编号
返回值:
成功:0
失败:非0
示例:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
    int i = 0;
    while (1)
    {
        sleep(1);
        printf("好无聊,想去死%d\n",i);
        if(i == 3)
        {
            printf("死给你看\n");
            raise(SIGKILL);
        }
        i++;
    }
    wait(NULL);
    return 0;
}
abort函数(自杀)
作用:给自己发送异常终止信号(6)SIGABRT,并产生core文件,等价于kill(getpid(),sig),自杀
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    char myfo[3] = {"我要发信号了","我真的要发信号了","拜拜了您呐"};
    int i = 0;
    while (1)
    {
        char *p = myfo[i];
        printf("%s\n",p);
        sleep(1);
        i++;
        if(i == 3)
        abort();
    }
    
    return 0;
}

alarm函数(自杀)
作用:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/time.h>
int main(int argc, char const *argv[])
{
    int seconds = 0;
    seconds = alarm(5);
    printf("计时器开始执行,seconds=%d\n",seconds);
    sleep(3);
    seconds = alarm(5);
    printf("计时器开始执行seconds=%d\n",seconds);
    while(1);
    return 0;
}

setitimer函数(计时器)
作用:
设置定时器(闹钟),可代替 alarm 函数。精度微秒 us,可以实现周期定时。
 
 
       #include <stdio.h>
#include <sys/time.h>
#include <signal.h>
void fun()
{
    printf("文件已被处理\n");
}
int main(int argc, char const *argv[])
{
    struct itimerval new_a;
    new_a.it_value.tv_sec = 5;
    new_a.it_value.tv_usec = 0;
    new_a.it_interval.tv_sec = 1;
    new_a.it_interval.tv_usec = 0;
    signal(SIGALRM,fun);
    setitimer(ITIMER_REAL,&new_a,NULL);
    while(1);
    return 0;
}

pause函数
作用:
将调用进程挂起直至捕捉到信号为止。这个函数通常用于判断信号是否已到
语法:
头文件:
#include <unistd.h>
函数:
int pause(void)
返回值:
知道捕获到信号,pause函数才返回-1,且errno被设置成EINTR
示例:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void fun()
{
    printf("进程已被执行\n");
}
int main(int argc, char const *argv[])
{
    printf("进程一开始,当前进程是%d\n",getpid());
    signal(SIGALRM,fun);
    alarm(3);
    int x = pause();
    printf("文件结束%d\n",x);
    return 0;
}
信号处理
方式
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void myfun()
{
    printf("自定义函数\n");
    _exit(0);
}
int main(int argc, char const *argv[])
{
    signal(SIGINT,myfun);
    while(1);
    return 0;
}

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
char *p;
void fun(int sigcode)
{
    if(p != NULL)
    {
        free(p);
        
    }
    printf("p空间被释放了\n");
    _exit(0);
}
int main(int argc, char const *argv[])
{
    p =malloc(50);
    strcpy(p,"helloSIG");
    signal(SIGINT,fun);
    while(1)
    {
        printf("%s\n",p);
        sleep(1);
    }
    return 0;
}

struct sigaction
{
void (*sa_handler)(int); // 旧的信号处理函数指针
void (*sa_sigaction)(int, siginfo_t *, void *); // 新的信号处理函数指针
sigset_t sa_mask; // 信号阻塞集
int sa_flags; // 信号处理的方式
void (*sa_restorer)(void); // 已弃用
};
/*
1,sa_handler,sa_sigaction:信号处理函数指针,和signal()里的函数指针用法
一样,应根据情况给 sa_sigaction、sa_handler 两者之一赋值,其取值如下:
a SIGIGN:忽略该信号
b SIGDFL:执行系统默认动作
c 处理函数名:自定义信号处理函数
2,sa_mask:信号阻塞集,在信号处理函数执行过程中,临时屏蔽指定的信号。
3,sa_flags:用于指定信号处理的行为,通常设置为 0,表使用默认属性。它可
以是以下值的“按位或”组合:
SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃)
SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD
信号。
SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这
时子进程如果退出也不会成为僵尸进程。
SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这
个信号。
SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理
函数
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>
#include <string.h>
void fun(int sigcode)
{
    printf("ctrl+c的信号编码是:%d\n",sigcode);
    _exit(-1);
}
int main(int argc, char const *argv[])
{
    struct sigaction cat;
    cat.sa_handler = fun;
    sigaction(SIGINT,&cat,NULL);
    while(1);
    return 0;
}

示例2::发出定义信号
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
void fun(int sigcode)
{
    printf("SIGUSR1得信号编号是:%d\n",sigcode);
    _exit(-1);
}
int main(int argc, char const *argv[])
{
    struct sigaction cat;
    cat.sa_handler = fun;
    sigaction(SIGUSR1,&cat,NULL);
    kill(getpid(),SIGUSR1);
    while(1);
    return 0;
}

可重入函数
 
 
   #include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void show(int pid)
{
    for(int i = 0;i < 3;i++)
    {
        char buf[50] = {0};
        sprintf(buf,"进程%d被%d次执行\n",pid,i,"\r\n");
        write(1,buf,sizeof(buf));
        sleep(1);
    }
}
int main(int argc, char const *argv[])
{
    for (int i = 0; i < 5; i++)
    {
        int pid = fork();
        if(pid == 0)
        {
            printf(getpid());
            _exit(-1);
        }
        else if(pid > 0)
        {
            printf("子进程%d被创建\n",pid);
            _exit(-1);
        }
    }
    while(1)
    {
        int id = waitpid(-1,NULL,WNOHANG);
        if(id > 0)
        {
            printf("子进程在被回收\n",id);
            sleep(1);
        }
        else if(id == 0)
        {
            break;
        }
    }
    return 0;
}

信号集
概述
 
 
 自定义信号集函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char const *argv[])
{
//定义一个信号集
sigset_t set;
//清空set集
sigemptyset(&set);
//将SIGINT添加到set集合中
sigaddset(&set, SIGINT);
//将SIGTSTP添加到set集和中
sigaddset(&set, SIGTSTP);
if (sigismember(&set, SIGINT))
{
printf("SIGINT是在set集合中\n");
}
else
{
printf("SIGINT不在set集合中\n");
}
//将SIGINT从集合中删除
sigdelset(&set, SIGINT);
if (sigismember(&set, SIGINT))
{
printf("SIGINT是在set集合中\n");
}
else
{
printf("SIGINT不在set集合中\n");
}
return 0;
}信号阻塞集
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char const *argv[])
{
//定义一个信号集
//vscode中编写的sigset_t会报错,不管
sigset_t set;
//清空set集
sigemptyset(&set);
//将SIGINT添加到set集合中
sigaddset(&set, SIGINT);
//将set集合添加到阻塞集
//vscode中编写的SIG_BLOCK,SIG_BLOCK会报错不管
sigprocmask(SIG_BLOCK, &set, NULL);
printf("SIGINT信号将在5秒后从阻塞集中删除\n");
sleep(5);
sigprocmask(SIG_UNBLOCK, &set, NULL);
while (1);
return 0;
}


![二叉树的层平均值[中等]](https://img-blog.csdnimg.cn/direct/e697aea08cf441f09a49aa9c1a88cbab.png)

















