笔记整理—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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值