0

对不起,如果我再次问同样的问题但想验证!

我有两个进程 P1 和 P2。

P1是作家(制片人)。
P2是一个读者(消费者)。

有一些共享内存或 P1 写入的文件,一旦 P1 写入,应该通知 P2 读取。

现在根据我的理解 P1 的伪代码应该是

打开共享文件
创建一个命名事件(“Writedone”)来表示 P2 进程的写入
对文件进行一些处理
互斥锁()
写入文件
互斥锁()
名为事件的信号。
CloseHandle 存档

现在在P2

打开共享文件的句柄
打开命名事件的句柄
命名事件上的 WaitForSingleEvent(“Writedone”)
从文件中读取
CloseHandle 存档

问题:

  1. 阅读器是否需要锁?阅读器只会读取文件而不更改它。所以我想读者不需要锁。想法?在没有锁的情况下会出错吗?
  2. 我每次在读写过程中都会打开和关闭文件的句柄。我认为这不是必需的。我可以在构造函数中打开文件句柄并在读写器的析构函数中关闭它。但是当它被用于写作时,我可以从文件中读取吗?

编辑:每次 writer 在 File 末尾写入 10 个字节,并且 reader 应该读取 writer 写入的最新 10 个字节。

4

5 回答 5

1

答案是:当(且仅当)两个线程可以同时使用相同的共享资源时,锁定是必要的。关于您的具体实施没有足够的信息,但我有几句话:

  1. 仅在写入期间锁定是没有意义的。它只会增加一些开销,但在阅读器也被正确锁定之前不会阻止任何并发访问。
  2. 如果修改与文件描述符相关的结构的文件操作未以任何方式同步,则锁定将是必要的。当 P2 仍在读取时,P1 可能会开始写入文件。如果读取和写入操作在没有任何底层同步的情况下修改相同的系统结构,您最终将得到损坏的数据。很难说这里是否是这种情况,因为您没有提及您使用了哪个特定功能(库)。文件操作在大多数系统上都是同步的,所以应该不是问题。
  3. 从您写的关于“10 字节信息部分”的内容来看,显式锁定似乎没有必要(除非#2 没有强加它)。P1 产生数据量。当数据准备好被读取时,P1 会通知 P2(通过事件;无论如何,事件传递应该在内部同步)。P2 知道它可以读取数据量,然后需要等待后续通知。可能会在处理前一个通知之前发送后续通知。因此,事件需要以某种方式排队。您还可以使用信号量代替事件通知。
于 2009-03-25T16:29:30.680 回答
0

您需要读者获得锁定 - 事件的使用是不可替代的。没有它,作者可以在阅读器代码的任何时候开始编写。

于 2009-03-25T14:27:03.003 回答
0

您绝对需要锁定消费者,以防止生产者在阅读器读取之前附加到文件。想象一下这个场景:

Producer writes and signals
Consumer receives signal
Consumer opens the file
Producer fires again and writes another 10 bytes
Producer signals
Consumer reads the last 10 bytes
Consumer closes the file

接下来会发生什么取决于您的命名事件是手动重置还是自动重置。如果它是自动重置的,那么消费者将看到第二个信号,然后返回并再次读取相同的内容。如果是手动重置,那么消费者将重置事件并错过生产者写的最后一件事。

请注意,即使使用锁,如果生产者能够足够快地响应,您也有竞争条件。也就是说,生产者可能能够在消费者能够读取第一条记录之前将第二条记录放入文件中。

看起来您在这里拥有的是在文件中实现的 FIFO 队列,并且您依赖于消费者处理数据的能力比生产者创建数据的速度更快。如果你能保证这种行为,那么你就可以了。否则,消费者将不得不跟踪它上次读取的位置,以便它知道接下来应该读取的位置。

于 2009-03-25T15:53:40.487 回答
0
  1. 如果作者可以随时开始写入,您确实需要锁定阅读器中的互斥锁。确保互斥锁是一个命名的,以便 P2 可以打开它。

  2. 如果在两个进程中都使用 FileShare.ReadWrite 打开文件,则可以将其保持打开状态。

在阅读器中,您可能必须先寻找到您点击 EOF 的地方,然后才能再次阅读。

如果您确定写入器始终在追加,并且您可以知道记录的结束位置(例如,因为它们始终是 10 个字节),并且您可以接受一个小的延迟,并且写入器总是写入完整的记录,那么您可以在没有互斥锁的情况下执行此操作和事件。使用 FileShare.ReadWrite 打开文件,然后在阅读器中,继续寻找同一个地方并尝试阅读您的记录,如果不能,则睡一秒钟。如果你设法读了整张唱片,你就得到了一张。找出你的位置并返回寻找那个地方并尝试再次阅读。这就是 tail -f 在 Unix 中的工作方式。

于 2009-03-25T16:03:31.163 回答
0

除了正常的同步功能外,您还可以使用 Windows 上的文件更改通知API 来等待文件更改。

于 2009-03-25T23:40:07.730 回答