进程间通信

  由于进程的地址空间是独立的,所以进程间交互数据必须采用专门的通信机制。Linux下进程间通信主要方法有管道(pipe fifo)、信号量(semophore)、消息队列、共享内存(shared memory)、信号(signal)、套接字(socket)。
  1. 管道:半双工(单向,却可逆)的通信方式。
    本质 伪文件 一旦被读取就不存在
    (1)匿名管道(pipe):只能用于有血缘关系的进程间(父子进程共享打开的文件描述符)
    原型Int pipe(int pipefd[2]); 注意管道两端的任务时间固定的fd[0]为管道读端,fd[1]为管道写端;
    (2)命名管道(FIFO):一个设备文件,提供了一个路径名与之关联,已FIFO的文件形式存储于文件系统中。注意:FIFO总是按照先进先出(First In First Out)的原则工作,第一个被写入的数据将首先从管道中读出。
    创建:Int mkfifo(const char *pathname,mode_t mode);

举例:父子进程间相互传输数据

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

#define BUFFSIZE 1024

int main()
{
    pid_t pid = -1;
    char buff[BUFFSIZE] = {'\0'};
    int pipefd_ps[2] = {-1};
    int pipefd_pr[2] = {-1};
    int rev = -1;

    rev = pipe(pipefd_pr) | pipe(pipefd_ps);
    if(-1 == rev)
    {
        perror("pipe error : ");
        return -1;
    }
    pid = fork();
    if(-1 == pid){
        perror("fork error : ");
        return -1;
    }
    else if(0 == pid){
        close(pipefd_ps[0]);
        close(pipefd_pr[1]);
        while(1){
            sleep(1);
            memset(buff,'\0',BUFFSIZE);
            strcpy(buff,"I'am parents ");
            rev = write(pipefd_ps[1],buff,strlen(buff));
            if(rev != strlen(buff)){
                perror("write error : ");
                return -1;
            }

            sleep(1);

            memset(buff,'\0',BUFFSIZE);
            strcpy(buff,"children said : ");
            rev = read(pipefd_pr[0],buff + strlen(buff) - 1,BUFFSIZE - strlen(buff));
            if(rev == 0){
                perror("read error : ");
                return -1;
            }
            strcat(buff,"\n");
            write(STDOUT_FILENO,buff,strlen(buff));
        }
    }
    else{
        close(pipefd_ps[1]);
        close(pipefd_pr[0]);
        while(1){
            sleep(1);
            memset(buff,'\0',BUFFSIZE);
            strcpy(buff,"parent said : ");
            rev = read(pipefd_ps[0],buff + strlen(buff) - 1,BUFFSIZE- strlen(buff));
            if(rev == 0){
                perror("read error : ");
                return -1;
            }
            strcat(buff,"\n");
            write(STDOUT_FILENO,buff,strlen(buff));

            sleep(1);

            memset(buff,'\0',BUFFSIZE);
            strcpy(buff,"I'am children ");
            rev = write(pipefd_pr[1],buff,strlen(buff));
            if(rev != strlen(buff)){
                perror("write error : ");
                return -1;
            }
        }
    }

    return 0;
}
  1. 信号:进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待 信号的到达,信号机制不仅有基本通知功能还可以传递附加信息。
    可以从两个不同的分类角度对信号进行分类:
    (1)可靠性方面:
    不可靠信号:信号值小于SIGRTMIN的信号。主要问题是信号可能丢失。
    可靠信号:这些信号支持排队,不会丢失。信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。

    (2)与时间的关系上:
    非实时信号都不支持排队,都是不可靠信号;
    实时信号都支持排队,都是可靠信号。

    信号的处理:
    (1)signal(int signum,sighandler_t handler);捕捉
    (2)int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));检查或设置进程在接收到信号时的动作
    (3)int pause(void);函数使调用进程挂起直到捕捉到一个信号。
    (4)int kill(pid_t pid,int sig);用来发送信号给直到的进程
    (5)int raise(int sig);给调用它的进程发送信号
    (6)sigqueue();发送信号
    (7)alarm/getitimer/settimer 用来设置定时器
    (8)abort()向进程发送SIGABORT信号

    信号的举例

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

//父进程每隔5S发送一个SIGQUIT给子进程 KILL 子进程 未收到信号 1S输出“”XXXDHR“
//收到信号输出 HELLO
void haha(int signum)
{
   printf("hello");
 }

void main()
{
   pid_t pid=1;
   //int signum=SIGQUIT;
   pid=fork();
   if(-1==pid)
   {
    return -1;

   }
   else if(0==pid)
   {
       signal(SIGQUIT,haha);
       while(1)
       {
       printf("LCDHR");
       sleep(1);
       printf(" ");
       }
       }

       else
       while(1)
       {
           printf("yuio");
           sleep(5);
           kill(pid,SIGQUIT);
           }
}
  1. 消息队列:一个存放在内核中的消息链表,每个消息队列由消息队列标识符标识。与管道不同的是消息队列存放在内核中,只有内核重启(即操作系统重启)或者显示地删除一个消息队列,该消息队列才会被真正删除。
    (1)创建:消息队列是随着内核 的存在而存在的,每个消息对列在系统范围内对应唯一的键值,要获得一个消息队列的描述符,只需提供该消息队列的键值即可。该键值通常由ftok返回。
    key_t ftok(const char *pathname,int proj_id)
    举例:ftok根据pathname,proj_id这两参数生成唯一的键值
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>

int main()
{
    int i;
    for(i = 1; i <= 5;i++ )
    {
       printf("key[%d] =  %ul \n",i,ftok(".",i));
           }
    exit(0);
}

运行结果如下:
key[1] = 16908424l
key[2] = 33685640l
key[3] = 50462856l
key[4] = 67240072l
key[5] = 84017288l

(2)写消息对列
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
(3)读消息队列
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
(4)获取和设置消息队列的属性
int msgctl(int msqid, int command, struct msgid_ds *buf);
msgctl系统调用对msqid标识的消息队列执行cmd操作,系统定义了3中如下cmd操作。
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列

  1. 共享内存:就是分配一块能被其他进程访问的内存
    (1)共享内存的建立
    void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t ffset);
    Int shmget(key_t key,int size,int shmflg);
    (参数key 由ftok获得,Size 文件大小 ,Shmflg 读写权限)
    (2)共享内存的操作:在使用共享内存前,必须通过shmat将其附加到进程的地址空间,进程与共享内存就建立了链接。shmat调用成功返回一个指向内存空间的指针,使用该指针就能访问共享内存了。
    Void * shmat(int shmid,const void *addr,int shmflg);
    (3)当进程结束使用共享内存区时,要通过shmdt断开与共享内存去的连接
    Int shmdt(void* shmaddr);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值