Linux进程间通信(一)——管道、信号量 .

一、Linux进程间通信方式 :有六种方式在两个程序间传递信息

 

        1、信号( Singal )

        2、管道 ( Pipe ) 及有名管道

        3、信号量 ( Semaphore )

        4、共享内存 ( SharedMessage)

        5、消息队列 ( MessageQueue )

        6、套接字  ( Socket )

 

     其中,共享内存是效率最高的。

 

二、具体介绍

 

        1、信号( Singal )   可以参考 linux多进程——进程组与会话、守护进程、信号通信  中的信号通信部分

 

        2、管道 ( Pipe ) 及有名管道

  

                管道分为有名和无名管道。

 

              无名管道用于父子进程间的通信。

 

      a、用pipe( )创建无名管道       

 

  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<memory.h>   
  5. #include<signal.h>   
  6.   
  7. void my_func(int);  
  8.   
  9. int main(){  
  10.     pid_t pid;  
  11.     int pfd[2];  
  12.     char *msg="pipe test program";  
  13.     char buf[100];  
  14.     int r,w;  
  15.     memset(buf,0,sizeof(buf));  
  16.     //创建一个无名管道。一定要在fork之前创建。这样子进程才能有同样的一个管道   
  17.     if(pipe(pfd)<0){  
  18.         printf("pipe create error!\n");  
  19.         exit(1);  
  20.     }  
  21.   
  22.     if((pid = fork())<0){  
  23.         printf("fork error!\n");  
  24.         exit(1);  
  25.     }else if(pid == 0){  
  26.         //close(pfd[0]);   //此句是测试异常的时候使用   
  27.         close(pfd[1]);  
  28.         sleep(3);  
  29.         if(r=read(pfd[0],buf,100)<0){  
  30.             printf("read error!\n");  
  31.             waitpid(pid,NULL,0);     //等待子进程退出后再退出   
  32.             exit(1);  
  33.         }else  
  34.             printf("child read from pipe: %s\n",buf);  
  35.         close(pfd[0]);  
  36.     }else{  
  37.         signal(SIGPIPE,my_func);    //当读端不存在时系统发出SIGPIPE信号   
  38.         close(pfd[0]);  
  39.         sleep(1);  
  40.         if(w=write(pfd[1],msg,strlen(msg))<0){  
  41.             printf("wirte error!\n");  
  42.             exit(1);  
  43.         }else  
  44.             printf("parent send msg to child!\n");  
  45.         close(pfd[1]);  
  46.         waitpid(pid,NULL,0);  
  47.     }  
  48.     return 0;  
  49. }  
  50.   
  51. void my_func(int sig){  
  52.     if(sig == SIGPIPE){  
  53.         printf("read not exist\n");  
  54.     }  
  55. }  
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>

void my_func(int);

int main(){
    pid_t pid;
    int pfd[2];
    char *msg="pipe test program";
    char buf[100];
    int r,w;
    memset(buf,0,sizeof(buf));
    //创建一个无名管道。一定要在fork之前创建。这样子进程才能有同样的一个管道
    if(pipe(pfd)<0){
        printf("pipe create error!\n");
        exit(1);
    }

    if((pid = fork())<0){
        printf("fork error!\n");
        exit(1);
    }else if(pid == 0){
        //close(pfd[0]);   //此句是测试异常的时候使用
        close(pfd[1]);
        sleep(3);
        if(r=read(pfd[0],buf,100)<0){
            printf("read error!\n");
            waitpid(pid,NULL,0);     //等待子进程退出后再退出
            exit(1);
        }else
            printf("child read from pipe: %s\n",buf);
        close(pfd[0]);
    }else{
        signal(SIGPIPE,my_func);    //当读端不存在时系统发出SIGPIPE信号
        close(pfd[0]);
        sleep(1);
        if(w=write(pfd[1],msg,strlen(msg))<0){
            printf("wirte error!\n");
            exit(1);
        }else
            printf("parent send msg to child!\n");
        close(pfd[1]);
        waitpid(pid,NULL,0);
    }
    return 0;
}

void my_func(int sig){
    if(sig == SIGPIPE){
        printf("read not exist\n");
    }
}

 

    b、标准流管道: popen() 

 

         这个函数会完成:创建管道、fork()、关闭相应的文件描述符、执行exec、执行函数中指定的命令    这一系列的操作。优点当然是省事啦,缺点必然是不灵活。popen( )返回的是文件指针所以要用标准IO操作。其中,第二个参数:" r " 表示命令的输出作为程序的输入;" w " 表示程序的输出作为命令的输入。另外要注意用pclose( ) 关闭文件流。两个函数出错

   

  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<memory.h>   
  5. #include<signal.h>   
  6.   
  7. int main(){  
  8.     FILE *fp;  
  9.     int pfd[2];  
  10.     char *cmd="ls -l";  
  11.     char buf[100];  
  12.     if((fp=popen(cmd,"r")) == NULL){  
  13.         printf("popen error\n");  
  14.         exit(1);  
  15.     }  
  16.     while(fgets(buf,100,fp)!= NULL){  
  17.         printf("from fp:%s",buf);  
  18.     }  
  19.     pclose(fp);  
  20.     return 0;  
  21. }  
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>

int main(){
    FILE *fp;
    int pfd[2];
    char *cmd="ls -l";
    char buf[100];
    if((fp=popen(cmd,"r")) == NULL){
        printf("popen error\n");
        exit(1);
    }
    while(fgets(buf,100,fp)!= NULL){
        printf("from fp:%s",buf);
    }
    pclose(fp);
    return 0;
}



 

     c、有名管道FIFO

   

       读数据的程序:

 

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>   
  4. #include<memory.h>   
  5. #include<errno.h>   
  6. #include<stdlib.h>   
  7.   
  8. #define FIFO "pipetest"   
  9. int main(int argc,char* argv[]){  
  10.     int fd,r;  
  11.     char buff[1024];  
  12.     if(access(FIFO,F_OK)==-1){       //判断管道是否存在,管道是不可以重复创建的   
  13.         if(mkfifo(FIFO,0666)<0){  
  14.             if(errno==EEXIST)  
  15.             printf("it already exist\n");  
  16.             printf("create fifo error! it already exist\n");  
  17.             exit(1);  
  18.         }  
  19.     }  
  20.     if((fd=open("in1",O_RDONLY))<0){  
  21.         printf("open in1 error!\n");  
  22.         return 1;  
  23.     }  
  24.     while(1){  
  25.         memset(buff,0,1024);  
  26.         if(r=read(fd,buff,1024)>0){  
  27.             printf("send to name pipe: %s\n",buff);  
  28.         }  
  29.     }  
  30.     close(fd);  
  31. }  
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>

#define FIFO "pipetest"
int main(int argc,char* argv[]){
    int fd,r;
    char buff[1024];
    if(access(FIFO,F_OK)==-1){       //判断管道是否存在,管道是不可以重复创建的
        if(mkfifo(FIFO,0666)<0){
            if(errno==EEXIST)
            printf("it already exist\n");
            printf("create fifo error! it already exist\n");
            exit(1);
        }
    }
    if((fd=open("in1",O_RDONLY))<0){
        printf("open in1 error!\n");
        return 1;
    }
    while(1){
        memset(buff,0,1024);
        if(r=read(fd,buff,1024)>0){
            printf("send to name pipe: %s\n",buff);
        }
    }
    close(fd);
}

        

       写数据的程序:

 

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>   
  4. #include<memory.h>   
  5. #include<errno.h>   
  6. #include<stdlib.h>   
  7.   
  8. #define FIFO "pipetest"   
  9. int main(int argc,char* argv[]){  
  10.     int fd,w;  
  11.     char buff[1024];  
  12.     if(argc<2){  
  13.         printf("Usage: ./%s <string>\n",argv[0]);  
  14.         exit(0);  
  15.     }  
  16.     sscanf(argv[1],"%s",buff);  
  17.     if(access(FIFO,F_OK)==-1){  
  18.         if(mkfifo(FIFO,0666)<0){  
  19.             if(errno==EEXIST)  
  20.             printf("it already exist\n");  
  21.             printf("create fifo error!\n");  
  22.             exit(1);  
  23.         }  
  24.     }  
  25.     if((fd=open("in1",O_WRONLY))<0){  
  26.         printf("open in1 error!\n");  
  27.         return 1;  
  28.     }  
  29.     if(w=write(fd,buff,1024)>0){  
  30.         printf("send to name pipe: %s\n",buff);  
  31.     }  
  32.     close(fd);  
  33. }  
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>

#define FIFO "pipetest"
int main(int argc,char* argv[]){
    int fd,w;
    char buff[1024];
    if(argc<2){
        printf("Usage: ./%s <string>\n",argv[0]);
        exit(0);
    }
    sscanf(argv[1],"%s",buff);
    if(access(FIFO,F_OK)==-1){
        if(mkfifo(FIFO,0666)<0){
            if(errno==EEXIST)
            printf("it already exist\n");
            printf("create fifo error!\n");
            exit(1);
        }
    }
    if((fd=open("in1",O_WRONLY))<0){
        printf("open in1 error!\n");
        return 1;
    }
    if(w=write(fd,buff,1024)>0){
        printf("send to name pipe: %s\n",buff);
    }
    close(fd);
}

 

            3、信号量

           信号量和信号通信( Signal )可不一样。信号量( Semaphore ) 是用于解决不同程序间的访问问题。即同步和互斥。

 

           同步是指多线程程序按照一定的顺序执行一段完整的代码。互斥指多线程程序访问同一个变量时只能有一个线程在访问。

 

                 信号量就是为了解决同步和互斥的IPC机制,信号量为0则没有资源,进程进入等待队列,直到资源被释放为止。

 

            信号量编程的步骤:

                1、创建信号量或获得在系统中已经存在的信号量

                          调用semget () 函数 。使用同一个信号量键值即可获得同一个信号量。

                 2、初始化信号量

                          使用semctl( ) 函数的SETVAL。当使用二维信号量时,初始化为1。

                 3、进行信号量的PV操作

                          调用semop( ) 。实现同步与互斥。

                 4、不需要信号量则从系统中删除

                          使用semclt( ) 函数的IPC_RMID 。

 

           一个操作方法的封装函数文件:     

 

  1. #include<stdio.h>   
  2. #include<fcntl.h>   
  3. #include<unistd.h>   
  4. #include<memory.h>   
  5. #include<errno.h>   
  6. #include<stdlib.h>   
  7.   
  8. #define FIFO "pipetest"   
  9. int main(int argc,char* argv[]){  
  10.     int fd,w;  
  11.     char buff[1024];  
  12.     if(argc<2){  
  13.         printf("Usage: ./%s <string>\n",argv[0]);  
  14.         exit(0);  
  15.     }  
  16.     sscanf(argv[1],"%s",buff);  
  17.     if(access(FIFO,F_OK)==-1){  
  18.         if(mkfifo(FIFO,0666)<0){  
  19.             if(errno==EEXIST)  
  20.             printf("it already exist\n");  
  21.             printf("create fifo error! it already exist\n");  
  22.             exit(1);  
  23.         }  
  24.     }  
  25.     if((fd=open("in1",O_WRONLY))<0){  
  26.         printf("open in1 error!\n");  
  27.         return 1;  
  28.     }  
  29.     if(w=write(fd,buff,1024)>0){  
  30.         printf("send to name pipe: %s\n",buff);  
  31.     }  
  32.     close(fd);  
  33. }  
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>

#define FIFO "pipetest"
int main(int argc,char* argv[]){
    int fd,w;
    char buff[1024];
    if(argc<2){
        printf("Usage: ./%s <string>\n",argv[0]);
        exit(0);
    }
    sscanf(argv[1],"%s",buff);
    if(access(FIFO,F_OK)==-1){
        if(mkfifo(FIFO,0666)<0){
            if(errno==EEXIST)
            printf("it already exist\n");
            printf("create fifo error! it already exist\n");
            exit(1);
        }
    }
    if((fd=open("in1",O_WRONLY))<0){
        printf("open in1 error!\n");
        return 1;
    }
    if(w=write(fd,buff,1024)>0){
        printf("send to name pipe: %s\n",buff);
    }
    close(fd);
}

 

                 调用的例子:

 

  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<sys/types.h>   
  4. #include<sys/ipc.h>   
  5. #include<sys/sem.h>   
  6. #include"semcom.c"   
  7.   
  8. int main(){  
  9.     pid_t pid;  
  10.     int semid;  
  11.     if((semid=semget(ftok(".",'a'),1,0666|IPC_CREAT))<0){   //创建信号量   
  12.         printf("semget error!\n");  
  13.         exit(1);  
  14.     }  
  15.     init_sem(semid,1);  
  16.     if((pid = fork())<0){  
  17.         printf("fork error!\n");  
  18.         exit(1);  
  19.     }else if(pid == 0){  
  20.         sem_p(semid);           //在未释放之前父进程无法访问   
  21.         printf("child is running......\n");  
  22.         sleep(3);  
  23.         printf("son is %d  wake\n",getpid());  
  24.         sem_v(semid);  
  25.     }else{  
  26.         sem_p(semid);  
  27.         printf("parent is running......\n");  
  28.         sleep(3);  
  29.         printf("parent is %d  wake\n",getpid());  
  30.         sem_v(semid);  
  31.         sleep(6);  
  32.         del_sem(semid);  
  33.     }  
  34.     return 0;  
  35. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值