零基础入门进程间通信:task 1(匿名管道与vscode使用)

时间:2024-11-08 07:04:37

//parent process
void Reader(int Rfd) 
{
    char buffer[1024] = {0};
    while (true)
    {
        buffer[0] = '\0';   //清空缓冲区,告诉读者,这是一个字符串   

        //从文件中读取字符串
        ssize_t n = read(Rfd, buffer, sizeof(buffer));   //sizeof(buffer) != strlen(buffer)
        if (n > 0)   //n是读取的字节数
        {
            buffer[n] = 0;   //字符串末尾加上'\0'
            cout << "Received message: " << buffer << endl;
        }
    }
    
}

总结

核心逻辑就是父进程用pipe打开一个内存级别的文件两次

父进程创建子进程

子进程调用W函数,父进程调用R函数

W函数就是借助pipefd[1]向文件缓冲区写入(write)

R函数就是借助pipefd[0]从缓冲区读取(read)

父进程等待子进程

易错解析

每次打开一个文件都会产生一个file结构,同时获得一个file结构对应的fd。

读方式打开,获得读方式的fd

写方式打开,获得写方式的fd

一个进程可以用不同的方式打开一个文件多次。

我们不可以通过建立全局字符串的方式去进行通信,因为子进程在修改字符串时,会发生写时拷贝。

所有进行进程通信的时候,所占用的区域属于OS管理,而不是某个进程。

匿名管道的特性

1.只有亲戚之间可以通信

2.管道只能单向通信

3.父子进程协同、互斥(限定资源的抢占特性)、同步通信的特性

eg:子进程休眠10s才写入一次,那父进程也别着急读,会等待一下进程(并不会读取空的管道,因为没有打印Received message:,说明直接没有读)

4.管道面向字节流

不管你写的是什么,在r端认为都是一个个字节,只负责读。所谓的格式区分,不是r端该干的活,这种特性就是字节流。

5.管道基于文件,而文件被打开的生命周期基于进程,所以进程结束,管道关闭。

6.管道是有固定大小的,在不同的内核中,可能有差别

7.管道的原子性

原子性:小于pipe_buf,就是原子的。保证读写的连贯性 4kb

管道的四种情况

读写端正常,管道为空,读端阻塞

读写端正常,管道满了,写段阻塞

写端关闭,read会读取到EOF,返回0,不会阻塞

读端关闭,写端继续写入时,OS就要(通过信号)杀掉写进程

写端关闭特指的是:一定要现有写端被打开的现象,才能说是写端被关闭。如果写端都哦没有被打开,就不存在关闭一说

在命名管道(FIFO)的情况下,"写端关闭"这个说法确实指的是写端曾经被打开,并且随后被关闭。以下是详细解释:

打开写端:这意味着至少有一个进程通过 open 系统调用以写模式(O_WRONLY)打开了管道的写端,从而能够向管道写入数据。

关闭写端:这发生在进程完成写入操作后,通过 close 系统调用关闭了写端。关闭写端意味着该进程不再向管道写入数据,但如果有其他进程已经打开了写端,它们仍然可以写入。

写端未被打开:如果没有任何进程以写模式打开管道的写端,那么我们就不能说写端被关闭,因为关闭是一个状态改变,需要先有一个打开的状态。

因此,如果没有进程曾经打开过写端,那么说“写端被关闭”是不准确的。在这种情况下,更准确的说法是“写端尚未被打开”或“没有进程打开写端”。

当读端进程尝试从管道读取数据时,如果写端尚未被任何进程打开,那么读操作会阻塞,等待写端的打开和数据的写入。只有当至少一个进程打开了写端并写入数据后,读端进程的读操作才会解除阻塞并读取数据。如果所有写端都被关闭,并且没有数据留在管道中,那么读操作会返回0,表示到达了文件末尾。

应用场景

在bash中输入的|管道符号就是一种匿名管道。