进程同步-管道和IPC

参考文章:https://blog.csdn.net/bit_clearoff/article/details/55105816

管道是进程间通信的方式之一,是在进程之间建立一个实现数据流通的通道,用来缓存要传输的数据。

每个管道有两个文件描述符,写和读。

例:父子进程通信,关闭无关的文件描述符,子->父,子关闭读,父关闭写。

管道特点:

1.管道没有名字。

2.管道是半双工的,数据单向流动,双向通信需要两个管道。

3.只能拥有有亲属关系的进程之间。

4.单独构成文件系统,并且只存在内存中。

5.缓冲区大小有限。

6.数据的写入和读出:一个进程写入的从管道另一边读出,写入在管道末尾,读出在缓冲区头部。

7.管道传送的是无格式字节流。

管道创建

void pipe_init()
{
    /*
      通过pipe创建一个管道,参数是一个int型pipefd[2],分别代表读和写。
     成功返回0,反之-1。
     */
    int fd[2];
    char readbuffer[20];
    char writebuffer[]="hello world";
    int temp=pipe(fd);
    if(temp<0)
    {
        cout<<"pipe creat error"<<endl;
        exit(0);
    }
    write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
    read(fd[0], readbuffer, sizeof(writebuffer));// 读出 size和write一样
    cout<<"管道读出的数据:"<<readbuffer<<endl;//输出读到的数据
    cout<<"管道的读文件符fd[0]:"<<fd[0]<<" 管道的写文件符fd[0]:"<<fd[1]<<endl;
    //结束时要关闭文件描述符
    close(fd[0]);
    close(fd[1]);
}

父子进程之间通信

(不知道为啥必须在if里面写fork 如果在外面创建pid read读区会出错误)

void pid_pipe1()//在父子进程中进行管道通信 父进程读 子进程写
{
    int fd[2];
    //char readbuffer[20];
    //char writebuffer[]="helloworld";
    pid_t pid;
    //pid=fork();
    int pe=pipe(fd);
    if(pe<0)
    {
        cout<<"pipe failed"<<endl;
        exit(1);
    }
    if(fork()==0)//child 不知道为啥必须在if里面写fork 如果在外面创建pid read读区会出错误
    {
        char writebuffer[12]="hello world";
        close(fd[0]);//子进程写操作 把读关了
        write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
        //write(fd[1], &writebuffer, 1);//管道写入数据
    }
    else//father
    {
        sleep(1);
        close(fd[1]);//父进程写操作 把写关了
        //char readbuffer[20];
        char readbuffer[12];
        read(fd[0], readbuffer, 12);// 读出 size和write一样
        cout<<"父进程中,管道读出的数据:"<<(readbuffer)<<endl;//输出读到的数据
        //printf("%s",readbuffer);
    }
    exit(0);
}

Linux的命名管道

命名管道和管道一样,都是实实在在的文件,但两者的区别在于,命名管道又一个路径名与之关联。管道的文件是不公开的,管道通信只是存在于有亲属关系的进程之中,但是和创建命名管道的进程没有亲属关系的进程,只要可以访问路径,两个进程就可以实现通信。

命名管道的工作方式

1 命名管道由shell创建,将数据从一条管道传递到另一条,无需创建中间临时文件。

2 用于客户进程和服务进程的应用程序,在客户进程和服务器进程之间传递数据。

ps:由于命名管道是文件格式,同一个名字的文件创建成功之后就不能再创建了。

void fun1(int argc, const char * argv[])//使用mkfifo函数创建命名管道
{
    mode_t mode=0755;//文件权限设置
    if(argc!=2)
    {
       // cout<<"请输入正确的文件参数"<<endl;
        //exit(0);
    }
    //成功返回0 反之返回-1 第一个参数是命名管道的文件路径名字
    if(mkfifo("mingmingguandao", mode)==0)
    {
        cout<<"命名管道创建成功"<<endl;
        //cout<<"创建失败"<<endl;
        //exit(1);
    }
    else
    {
        cout<<"创建失败"<<endl;
        exit(1);
    }
}

创建失败的原因是已经创建成功,文件已经存在。

匿名管道(普通管道)完整程序和参考代码

//
//  main.cpp
//  Linux进程同步-管道和IPC
//
//  Created by 蓝猫 on 2018/11/8.
//  Copyright © 2018年 蓝猫. All rights reserved.
//

#include <iostream>
#include <sys/types.h>
#include <unistd.h>

using namespace std;
/*
 管道是进程间通信的方式之一,是在进程之间建立一个实现数据流通的通道,用来缓存要传输的数据。
 每个管道有两个文件描述符,写和读。
 例:父子进程通信,关闭无关的文件描述符,子->父,子关闭读,父关闭写。
管道特点:
1.管道没有名字。
2.管道是半双工的,数据单向流动,双向通信需要两个管道。
3.只能拥有有亲属关系的进程之间。
4.单独构成文件系统,并且只存在内存中。
5.缓冲区大小有限。
6.数据的写入和读出:一个进程写入的从管道另一边读出,写入在管道末尾,读出在缓冲区头部。
7.管道传送的是无格式字节流。
 
 */

void pipe_init()
{
    /*
      通过pipe创建一个管道,参数是一个int型pipefd[2],分别代表读和写。
     成功返回0,反之-1。
     */
    int fd[2];
    char readbuffer[20];
    char writebuffer[]="hello world";
    int temp=pipe(fd);
    if(temp<0)
    {
        cout<<"pipe creat error"<<endl;
        exit(0);
    }
    write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
    read(fd[0], readbuffer, sizeof(writebuffer));// 读出 size和write一样
    cout<<"管道读出的数据:"<<readbuffer<<endl;//输出读到的数据
    cout<<"管道的读文件符fd[0]:"<<fd[0]<<" 管道的写文件符fd[0]:"<<fd[1]<<endl;
    //结束时要关闭文件描述符
    close(fd[0]);
    close(fd[1]);
}
void pid_pipe1()//在父子进程中进行管道通信 父进程读 子进程写
{
    int fd[2];
    //char readbuffer[20];
    //char writebuffer[]="helloworld";
    pid_t pid;
    //pid=fork();
    int pe=pipe(fd);
    if(pe<0)
    {
        cout<<"pipe failed"<<endl;
        exit(1);
    }
    if(fork()==0)//child
    {
        char writebuffer[12]="hello world";
        close(fd[0]);//子进程写操作 把读关了
        write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
        //write(fd[1], &writebuffer, 1);//管道写入数据
    }
    else//father
    {
        sleep(1);
        close(fd[1]);//父进程写操作 把写关了
        //char readbuffer[20];
        char readbuffer[12];
        read(fd[0], readbuffer, 12);// 读出 size和write一样
        cout<<"父进程中,管道读出的数据:"<<(readbuffer)<<endl;//输出读到的数据
        //printf("%s",readbuffer);
    }
    exit(0);
}
int fun1()
{
    int filedes[2];
    //pid_t pid;
    //pid=fork();
    char buf[10];
    char out[10];
    pipe(filedes);
    if(fork() ==0)
    {
        close(filedes[0]);//子进程写操作 把读关了
        sprintf(buf,"%s","ab");
        write(filedes[1],buf,sizeof(buf));
    }
    else
    {
        close(filedes[1]);//子进程写操作 把读关了
        read(filedes[0],out,sizeof(buf));
        printf("%s\n",out);
    }
    return 0;
}
int fun2()
{
    //create pipe
    int fd[2]={0,0};
    if(pipe(fd)!=0){
        //create false
        perror("pipe");
        exit(1);
    }
    // pipe create success
    pid_t id=fork();
    if(id==0){
        //child -->write fd[1]
        printf("Child\n");
        sleep(2);
        const char* msg="Hello,leap\n";
        close(fd[0]);
        int count=3;
        while(count--){
            ssize_t size=write(fd[1],msg,strlen(msg));
            printf("size:%d\n",size);
            //if(count--){
            //  sleep(1);
            //}
            sleep(1);
            printf("child is writing...\n");
        }
        close(fd[1]);
        exit(0);
    }
    else{
        //father -->read fd[0]
        printf("Father\n");
        sleep(2);
        close(fd[1]);
        char buf[1024];
        int count=3;
        while(1){
            ssize_t Len=read(fd[0],buf,1024);
            //printf("Len::%d\n",Len);
            printf("Father is reading...\n");
            if(Len>0){
                //read success
                buf[Len]='\0';
                printf("child say:%s",buf);
            }
            else if(Len==0){
                //read end of file
                printf("Read the end of pipe\n");
                break;
            }
            else{
                perror("read");
                exit(1);
            }
        }
        close(fd[0]);
        int status=0;
        pid_t _pid=waitpid(id,&status,0);
        if(_pid==id){
            printf("Wait success for child\n");
            printf("Exit code:%d,Exit signal:%d\n",(status>>8)&0xff,status&0xff);
        }
        else{
            perror("wait");
        }
        exit(0);
    }
    return 0;
}
int main(int argc, const char * argv[])
{
    pid_pipe1();
    //fun2();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/BJUT_bluecat/article/details/83894989