管道为什么是半双工的呢?

发布于 2022-09-07 07:50:45 字数 31 浏览 34 评论 0

从源码的角度来看,为什么管道不得不是半双工的呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

丢了幸福的猪 2022-09-14 07:50:45

Linux的管道实现是个环形缓冲区:

/**
 *    struct pipe_buffer - a linux kernel pipe buffer
 *    @page: the page containing the data for the pipe buffer
 *    @offset: offset of data inside the @page
 *    @len: length of data inside the @page
 *    @ops: operations associated with this buffer. See @pipe_buf_operations.
 *    @flags: pipe buffer flags. See above.
 *    @private: private data owned by the ops.
 **/
struct pipe_buffer {
    struct page *page;
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;
    unsigned int flags;
    unsigned long private;
};


/**
 *    struct pipe_inode_info - a linux kernel pipe
 *    @mutex: mutex protecting the whole thing
 *    @wait: reader/writer wait point in case of empty/full pipe
 *    @nrbufs: the number of non-empty pipe buffers in this pipe
 *    @buffers: total number of buffers (should be a power of 2)
 *    @curbuf: the current pipe buffer entry
 *    @tmp_page: cached released page
 *    @readers: number of current readers of this pipe
 *    @writers: number of current writers of this pipe
 *    @files: number of struct file referring this pipe (protected by ->i_lock)
 *    @waiting_writers: number of writers blocked waiting for room
 *    @r_counter: reader counter
 *    @w_counter: writer counter
 *    @fasync_readers: reader side fasync
 *    @fasync_writers: writer side fasync
 *    @bufs: the circular array of pipe buffers
 *    @user: the user who created this pipe
 **/
struct pipe_inode_info {
    struct mutex mutex;
    wait_queue_head_t wait;
    unsigned int nrbufs, curbuf, buffers;
    unsigned int readers;
    unsigned int writers;
    unsigned int files;
    unsigned int waiting_writers;
    unsigned int r_counter;
    unsigned int w_counter;
    struct page *tmp_page;
    struct fasync_struct *fasync_readers;
    struct fasync_struct *fasync_writers;
    struct pipe_buffer *bufs;
    struct user_struct *user;
};

curbuf是当前缓存区的下标,每个缓冲区里有offset和len记录数据写到的位置,读写的时候是要修改这些信息的。

如果两个进程同时进行读或者同时进行写,必要会导致数据冲突,所以内核会对管道上锁(pipe_inode_info里的mutex),所以是半双工的。

比较简单的实现可以看xv6的实现

struct pipe {
  struct spinlock lock;
  char data[PIPESIZE];
  uint nread;     // number of bytes read
  uint nwrite;    // number of bytes written
  int readopen;   // read fd is still open
  int writeopen;  // write fd is still open
};

直接一块连续的内存data,用两个数字nreadnwrite记录读写数,通过PIPESIZE取模得到在data上的读写位置,用自旋锁保护。如果没有锁,两个进程就能同时写数据到data和修改nwrite,数据也就冲突了,同时读也同理。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文