进程间通信

说明


无名管道(pipe)
命名管道(fifo)
内存映射(mapped memeory),
消息队列(message queue)
共享内存(shared memory)
信号量(semaphore)
信号(signal)
文件(file)
套接字(Socket)

无名管道

在具有亲缘进程间的单向管道
读写的是一个
注意控制,流向的方法

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>

int main() {
    using std::cout;
    using std::endl;
    using std::string;
    using std::to_string;
    int pipe_fd[2];
    const int MAX_BUF_LENGTH = 256;
    char buf[MAX_BUF_LENGTH];
    string  data  = "Pip test program";
    
    memset(buf,0,sizeof(buf));
    if (pipe(pipe_fd) < 0) {
        cout << "Pipe create error.\n";
        exit(1);
    }
    else {
        pid_t pid = fork();
        if (pid == 0) {
            close(pipe_fd[1]);
            int real_read;
            if ((real_read = read(pipe_fd[0],buf,MAX_BUF_LENGTH)) > 0) {
                cout << "get = [" << real_read << "] = " << buf << "\n";
            }
            close(pipe_fd[0]);
            return 0;
        }
        else if (pid > 0) {
            close(pipe_fd[0]);
            int real_write;
            if ((real_write = write(pipe_fd[1],data.c_str(),data.size())) != -1) {
                cout << "send = [" << real_write << "] = " << data << endl;
            }
            close(pipe_fd[1]);
            wait(0);
            return 0;
        }
        else {
            cout << "Unknow pid = " << pid << endl;
        }
    }
    return 0;
}

命名管道

FIFO(命名管道)不同于匿名管道之处在于它提供⼀个路径名与之关联,以FIFO的⽂件形式存储于⽂件系统中。命名管道是⼀个设备⽂件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则⼯作,第⼀个被写⼊的数据将⾸先从管道中读出。


就是创建一个可以在文件系统长寻找的设备,通过该设备进行,通信
注意设备不能重复创建,需要一定的判断,以及注意设备的权限问题
这个设备标记了内核中的一块缓冲区所以对读写没有什么限制,可以多次、多进程去写、读

read.cpp

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string>
const std::string PATH = "./fifo";
const int SIZE = 128;
int main() {
    umask(0);
    if (mkfifo(PATH.c_str(),0666 | S_IFIFO) == -1) {
        perror ("mkefifo error");
        // exit(0);
    }
    int fd = open(PATH.c_str(),O_RDONLY);
    if (fd < 0) {
        printf("open fd is error\n");
        return 0;
    }
    else {
        char Buf[SIZE];
        while(1) {
            ssize_t s = read(fd,Buf,sizeof(Buf));
            if (s < 0) {
            perror("read error");
            exit(1);
            }
            else if (s == 0) {
                printf("client quit! i shoud quit!\n");
                break;
            }
            else {
                Buf[s] = '\0';
                printf("client# %s ",Buf);
                fflush(stdout);
            }
        }
        close(fd);
    }
    return 0;
} 

write.cpp

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>

const std::string PATH = "./fifo";
const int SIZE = 128;
int main() {
    int fd = open(PATH.c_str(),O_WRONLY);
    if (fd < 0) {
        perror("open error");
        return 0;
    }
    else {
        char Buf[SIZE];
        while(1) {
            printf("please Enter#:");
            fflush(stdout);
            ssize_t s = read(0,Buf,sizeof(Buf));
            if (s < 0) {
                perror("read is failed");
                return 1;
            }
            else if(s == 0) {
                printf("read is closed!");
                return 1;
            }
            else {
                Buf[s]= '\0';
                write(fd,Buf,strlen(Buf));
            }
        }
    }
 return 0;
}

内存映射

也可以用来拷贝文件

具有亲缘关系的进程之间

注意需要往文件里面写点东西,否则会出bus error
原因是mmap无法扩展空的物理页
也可以使用匿名文件,没有太大区别

#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main() {
    int fd = open("./english.txt",O_RDWR | O_CREAT,0644);
    if (fd == -1) {
        perror("open = ");
        return 1;
    }
    else {
        write(fd,"1",1);
        void* ptr = mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
        if (ptr == MAP_FAILED) {
            perror("mmap");
            return 1;
        }
        else {
            pid_t pid = fork();
            if (pid > 0) {
                const char * const data = "I'm parrent,who are you?";
                memcpy(ptr,data,strlen(data) + 1);
            }
            else if (pid == 0) {
                printf("Get data [%s]\n",static_cast<char*>(ptr));
            }
            munmap(ptr,1024);
        }
        sleep(1);
    }
    return 0;
}

陌生进程之间

write.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
int main() {
	int fd = open("./english.txt",O_RDWR | O_CREAT,0644);
    write(fd,"1",1);
	void* ptr = mmap(NULL,4000,PROT_READ | PROT_WRITE,
                     MAP_SHARED,fd,0);
	if (ptr == MAP_FAILED) {
        perror("mmap");
        return 0;
    }
    else {
        const std::string str = "Hi,I'm parrent.";
        memcpy(ptr,str.c_str(),str.size() + 1);
        munmap(ptr,4000);
    }
    return 0;
}

read.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
int main() {
	int fd = open("./english.txt",O_RDWR);
	void* ptr = mmap(NULL,4000,PROT_READ | PROT_WRITE,
                     MAP_SHARED,fd,0);
	if (ptr == MAP_FAILED) {
        perror("mmap");
        return 0;
    }
    else {
        printf("[%s]\n",static_cast<char*>(ptr));
        munmap(ptr,4000);
    }
    return 0;
}

消息队列

共享内存

信号量集

信号量集其实就是一个计数器数组,只能控制进程数量而不能互发数据。
key_t key = 8888;这里也可以同ftok(path,id)生成,大概 = id + hash(path)

g++ -oa a.cpp sem.cpp
g++ -ob b.cpp sem.cpp
./a & ./b
printf "\n"
sleep 5

sem.h

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/sem.h>

union semun {
    int val;
};

void sem_init();
void sem_p();
void sem_v();
void sem_destroy();

sem.cpp

#include "sem.h"

static int semid = -1;

void sem_init() {

    key_t key = 8888;
    semid = semget(key,1,IPC_CREAT | IPC_EXCL | 0600 );

    if (semid == -1) {
        semid = semget(key,1,IPC_CREAT);
        if (semid == -1) {
            perror("semget create error");
            return;
        }
    }
    else {
        union semun tmp;
        tmp.val = 1;
        if (semctl(semid,0,SETVAL,tmp) == -1) {
            perror("semctl初始化失败");
            return;
        }
    }
}

void sem_p() {
    sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;
    if (semop(semid,&buf,1) == -1) {
        perror("semop error");
        return;
    }
}

void sem_v() {
    sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    if (semop(semid,&buf,1) == -1) {
        perror("semop error");
        return;
    }
}
void sem_destroy() {
    if (semctl(semid,0,IPC_RMID) == -1) {
        perror("destory error");
    }
}

a.cpp

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "sem.h"
int main() {
    sem_init();
    for (int i = 0;i < 3;++i) {
        sem_p();
        write(1,"a",1);
        sleep(rand() % 3);
        write(1,"a",1);
        sem_v();
        sleep(rand() % 3);
    }
    sem_destroy();
    return 0;
}

b.cpp

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "sem.h"
int main() {
    sem_init();
    for (int i = 0;i < 3;++i) {
        sem_p();
        write(1,"b",1);
        sleep(rand() % 3);
        write(1,"b",1);
        sem_v();
        sleep(rand() % 3);
    }
    return 0;
}

信号

posted @ 2022-06-04 20:10  XDU18清欢  阅读(13)  评论(0)    收藏  举报