笔记整理—linux进程部分(6)进程间通信、alarm和pause

两个进程间通信可能是任何两个进程间的通信(IPC)。同一个进程是在同一块地址空间中的,在不同的函数与文件以变量进程传递,也可通过形参传递。2个不同进程处于不同的地址空间,要互相通信有难度(内存隔离的原因)本质上也是为了安全。

多数情况下是不会使用进程间通信的,大部分都是单进程,多线程只有在设计复杂的大型程序时候才会去使用IPC(如GUI或服务器)。IPC在中小程序上是用不上的。

linux提供四类进程间通信的方法,①管道,有名管道、无名管道。②system V IPC信号量、消息队列、共享内存。③socket套接字(一般用于网络通信)。④信号。

进程间通信IPC不常用的问题:①日常用的少,大程序才用得上。②很复杂,是linux应用编程中难度极大的部分。③细节很多。④初学困难。

管道:只允许读一次,一般情况下所说的管道是无名管道,若使用有名管道一般称为FIFO。无名管道通信原理,内核维护的一块内存,有读/写端。

管道是单向通信的,半双工的,但是一般被视为单工通信。单工通信,从左到右,单向运动。半双工,同一时间内从左到右,下一时刻能从右往左。全双工,同时支持双向运动。

为什么一般要把管道通信做成单工通信呢,其原因是,在双方都有读写的情况下进程A可能会把自己写的读写读走,让B进程没地方读信息,所以一般情况下,管道通信做的都是单工通信,本质上就是因为公共区域没区分,会发生抢读。所以就可以把这半双工通信作如下的操作:

无名管道通信,只能在父子之间进行通信父进程先创建pipe的带两个文件fd,pipe fd[2]。父进程fork子进程基础fd,父进程关闭读(或写),子进程关闭写(读)。只能在父子之间通信,这些缺点被有名管道进行修复。

有名管道,也是内核维护的一块内存,表现为一个有名字的文件,用两个进程去mkfifo创建fifo文件,通过open打开达到fd,进行通信,不要求目标为父子进程,因为这里有真实的文件存在。

system V IPC其有专用的API进程实现。分为三种方法,信号量,消息队列,共享内存。实际上用的也是内核提供的公共内存。

消息队列本质上是一个队列FIFO,内核内部维护一个FIFO,工作时A可以从队列中放东西,B从队列中读东西。

信号量,实质是一个计数器,一个计数的变量,主要用于互斥与同步(进程间互斥与资源同步等),就一个flag,可以做锁。

共享内存,内核中用一片内存,这块区域可以共同使用。

大片内存共享:A(摄像头)--------->B(视频编码)--------->C(视频传输)

方法①:A得到一个图像信息,复制给B一份,B去处理。

方法②:A和B用同一块内存空间共同处理图像。

实例就是LCD映射,LCD显存与代码共享一个内存空间存放图像。

共享内存适合进行大信息处理。

信号通信方式,是一种内容收到限制的异步通信机制。用于进程间通信或进程与内核通信;通信内容受到限制,只是一个信号;信号是异步的,不在同一个时钟,信号具有滞后性,同样和中断一样有不可预知性。信号的本质就是一个数字。

信号由谁处理------>进程。处理的方式有三种①忽略信号。②驳货信号(信号绑定了一个函数)。③默认处理,忽略或终止进程。不去主动的明确忽略信号,捕获信号,则会默认处理信号。

常见的信号有:

SIGINT    值为2    作用为ctrl+c时OS送给前台进程组中每个进程。
SIGPOLL/SIGIO    值为8    提示一个异步IO事件
SIGKILL    值为9    杀死进程的最终方法(不可忽略)
SIGALARM    值为14    与alarm闹钟相关
SIGCHLD    值为17    子进程停止或终止时OS向父进程发送,如wait()等待收尸

进程处理信号的方式:

sighandler_t signal(int signum, sighandler_t handler);

sighandler_t handler就是处理的方法相当于中断里面的处理函数,信号与槽里面的槽函数

typedef void (*sighandler_t)(int);

处理SIGINT信号默认终止进程(异常退出)

typedef void (*sighandler_t)(int);

void func(int sig)
{
    printf("signal:%d\n",sig);
}

int mian(void)
{
    signal(SIGINT,func);//主动捕获,默认终止进程
    while(1);
}

signal()返回值①返回正确的处理方法(成功)
             ②返回errnuber(SIG_ERR失败)

SIG_ERR是一个函数指针,signal返回无论正确与否都返回一个函数指针。SIG_ERR值为强制转换的-1表示err;SIG_DFL值为强制转换的0表示默认;SIG)IGN值为强制转换的1表示忽略。

signal(SIGINT,SIG_DFL)指定SIGINT为默认处理;signal(SIGINT,SIG_IGN)指定SIGINT为忽略处理。但是当使用signal()去绑定处理函数时可能会出现因为版本问题的错误。可以使用:

 int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

可以保证signal的其移植性。

 struct sigaction {
               void     (*sa_handler)(int);//signal中的方法
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };
通过传递NULL可以返回旧的处理方法

alarm函数,闹钟------到店了应该干什么。

unsigned int alarm(unsigned int seconds);

时间到了,返回一个SIGALRM信号,若传一个0,会取消之前没执行完的闹钟,在一个闹钟没完成时,会返回剩余时间。

typedef void (*sighandler_t)(int);

void func(int sig)
{
    printf("signal:%d\n",sig);
}

int main()
{
    unsigned int ret=-1;
    signal(SIGALRM,func);
    ret=alarm(3);
    while(1);
}

struct sigaction act={0};act.sa_handler=func;sigaction(SIGALRM,&act,NULL);对上面进行替换。

typedef void (*sighandler_t)(int);

void func(int sig)
{
    printf("signal:%d\n",sig);
}

int main()
{
    unsigned int ret=-1;
    struct sigaction act={0};
    act.sa_handler=func;
    sigaction(SIGALRM,&act,NULL);
    ret=alarm(3);
    while(1);
}

内核只给一个进程提供一个alarm时钟,只能定一个闹钟,一个没结束再次调用将会返回上一个闹钟还剩余的时间,覆盖闹钟重新计时。

pause函数,使进程挂起,让进程暂停运行,交出cpu,利用该函数使进程卡住,要退出该函数需要信号进行输入,进程被唤醒。所以可以使用alarm与pause模拟sleep()。

typedef void (*sighandler_t)(int);

void func(int sig)
{
}

void my_sleep(unsigned int seconds)
{
    struct sigaction act={0};
    act.sa_handler=func;
    sigaction(SIGALRM,&act,NULL);
    alarm(seconds);
    pause();
}

int main()
{
    my_sleep(1);
    printf("hi\n");
    my_sleep(4);
    printf("I am\n");
    my_sleep(3);
    printf("jack\n");
    return 0;
}
相关推荐
music score12 分钟前
Ubuntu编译fftw3
linux·ubuntu·postgresql
倔强的石头10615 分钟前
【C语言指南】数据类型详解(下)——自定义类型
c语言·开发语言·html
s_little_monster24 分钟前
【C++】多态(下)
开发语言·c++·经验分享·笔记·学习
陈苏同学29 分钟前
《动手学深度学习》笔记2.5——神经网络从基础→使用GPU (CUDA-单卡-多卡-张量操作)
人工智能·pytorch·笔记·python·深度学习·神经网络·机器学习
cozil1 小时前
CentOS常用命令收集
linux·运维·centos
薛定谔方程难1 小时前
【Linux】模拟实现一个shell
linux·运维·服务器
7yewh1 小时前
C语言刷题 LeetCode 30天挑战 (七)哈希计数法
linux·c语言·c++·嵌入式硬件·算法·leetcode·哈希算法
躺平救援队2 小时前
51单片机的串口
单片机·嵌入式硬件·51单片机
多多*2 小时前
OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建
java·linux·开发语言·前端·数据库·microsoft·架构
汽车电子助手2 小时前
【STM32开发环境搭建】-4-在STM32CubeMX中新增Keil(MDK-ARM) 5的工程目录(包含指定路径的C和H文件)
c语言·arm开发·stm32·stm32cubemx·keil