【问题标题】:Implementing pipe using shared memory & semaphores使用共享内存和信号量实现管道
【发布时间】:2013-01-27 06:00:10
【问题描述】:

我正在尝试使用共享内存和信号量来实现管道(可能我还需要信号来完成我的实现)

我遇到了如何正确设置信号量的算法问题。

假设我已经为管道缓冲区分配了一块共享内存, 和一块用于管道信息的共享内存(例如管道中有多少字节等......)

  1. 我想创建互斥(一次只有一个读取器/写入器使用管道)
  2. 如果读者想从空管道中读取,我应该阻止他,直到作者写了一些东西
  3. 与 '2' 相同,但写入完整管道的作家

我试图寻找答案,但我没有找到任何答案,尽管这似乎是一个常见的练习......

我知道一个名为“有界缓冲区问题”或“消费者生产者问题”的解决方案 这是这样实现的:

有 3 个信号量: 互斥 - 初始化为 1 full - 初始化为 0 空 - 初始化为 n(而 n 是管道中的“字节”数)

消费者代码:

wait(full)
wait(mutex)

remove a byte from the pipe

signal(mutex)
signal(empty)

生产者代码:

wait(empty)
wait(mutex)

add a byte to the pipe

signal(mutex)
signal(full)

此解决方案中的问题(用作我的问题的解决方案)是在给定时间内,仅从管道读取或写入一个字节。

在我的问题中 - 实现管道,我不确定作家将写入多少字节。如果他想写'n'个字节,那么他只有在管道中有位置的情况下才会写,如果没有,他会写少于'n'个字节......

这意味着写入者在写入之前必须检查管道中有多少可用空间。这是一个问题——因为作者会在没有互斥的情况下触及关键部分(管道的信息)..

所以我想把这部分放在关键部分,但是 - 如果一个作家想要写作并且管道已满 - 我怎么能只让一个读者在里面,然后让作家写更多?

我有点糊涂了……

任何帮助将不胜感激,谢谢!

【问题讨论】:

  • SYSV 消息队列或 POSIX 消息队列适用于此类任务。它们是内核持久的,只需要发送和获取调用。
  • 这看起来还不错。
  • @vonbrand 这不是很好(我认为),看看下一个场景:一个想要写 'n' 字节的作家检查管道中有多少字节,并且有空间多 2 个字节。因此作者将写入 2 个字节并完成(这就是管道的工作方式,不是吗?).. 现在:如果作者获得此信息,他可以写 2 个字节,然后控制权交给阅读器,阅读器读取'10 bytes',然后控制权返回给可以写入 12 个字节而不是 2 个字节的写入器……但他不知道
  • 你不是“看有没有空间,有没有再写”,你要求空间(减少free信号量,如果可以的话,你就等到有),然后写。看看greenteapress.com/semaphores,当然可以处理不是按 1 而是按任意数量递增/递减的信号量。
  • @vonbrand ,作为一个想要读取 2 个字节的读者,我需要检查是否有 2 个字节要读取.. 如果只有一个字节,那么我会读取一个字节和'我会走开(像管子一样).. 不是吗?我知道信号量不能增加/减少 1,但事实并非如此

标签: c signals pipe shared-memory semaphore


【解决方案1】:

没有必要拥有这么多互斥锁或将它们锁定这么长时间。在单一生产者/消费者场景中,生产者无需担心可用空间减少(它是唯一可以用完该空间的空间),消费者也同样如此。因此你的伪代码应该是:

制片人

while (lock_and_get_free_space() < bytes_to_write)
    wait()
unlock()

write(bytes_to_write)

lock_and_update_free_space()

消费者

while (lock_and_get_data() < bytes_to_read)
    wait()
unlock()

read(bytes_to_read)

lock_and_update_free_space()

【讨论】:

  • 这会导致死锁是bytes_to_write >= free_space && bytes_to_read >= n - free_space,例如n == 2, free_space = 1, bytes_to_write == 2, bytes_to_read == 2。此外,您似乎在等待互斥锁,这肯定会给您带来死锁。
  • @wich 应该设计缓冲系统,以便您在 w.r.t 中读取/写入合理数量的数据。缓冲区大小。伪代码中的wait 常表示“释放并等待”;例如查看pthread_cond_wait 的行为
  • 您可以读取/写入大量数据 w.r.t。缓冲区大小 这没有任何意义,一次读取或写入 n 个字节是正常的。
  • @CongXu 你能解释一下lock_and_get_free_space()wait()lock_and_get_data()lock_and_update_free_space() 是做什么的吗?所以我会理解伪代码...谢谢!
  • @hudac 假设您正在使用 pthreads,lock_and_get_free_space() 执行 pthread_lock plus 获取缓冲区可用空间(缓冲区容量减去缓冲区大小),waitpthread_cond_waitlock_and_update_free_space()是一个pthread_lock,更新缓冲区大小(因为你刚刚写了它)和pthread_unlock
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 2010-10-26
相关资源
最近更新 更多