代码之家  ›  专栏  ›  技术社区  ›  anand

读写器问题

  •  0
  • anand  · 技术社区  · 17 年前

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

    我有两个过程,p1和p2。

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

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

    根据我的理解,p1的伪代码应该是

    Open shared file
    Create a named event("Writedone") to signal write for P2 process
    Do some processing on file
    Mutex.Lock()
    Write to File
    Mutex.Unlock()
    Signal named Event.
    CloseHandle on file
    

    现在在P2

    Open handle to Shared file
    Open handle to named event
    WaitForSingleEvent on named event("Writedone")
    Read from file
    CloseHandle on file
    

    问题:

    1. 读卡器需要锁吗?读卡器只读取文件而不更改它。所以我想读者不需要锁。思想?在没有锁的情况下会出问题吗?
    2. 在读写过程中,我每次都打开和关闭该文件的句柄。我想这不是必须的。我可以在构造函数中打开文件句柄,并在读写器的析构函数中关闭它。但是我可以从文件中读出来吗?

    编辑:每次编写器在文件末尾写入10个字节,读卡器应该读取编写器写入的最新10个字节。

    5 回复  |  直到 17 年前
        1
  •  1
  •   oo_olo_oo    17 年前

    答案是:如果(并且仅当)两个线程可以同时使用相同的共享资源,则需要锁定。关于您的具体实施,没有足够的信息,但我没有什么评论:

    1. 仅在写入时锁定是没有意义的。它只会增加一些开销,但不会阻止任何并发访问,直到读卡器也被正确锁定。
    2. 如果修改与文件描述符连接的结构的文件操作未以任何方式同步,则需要进行锁定。当p2仍在读取时,p1可能会开始写入文件。如果读写操作在没有任何底层同步的情况下修改相同的系统结构,那么最终将导致数据损坏。很难说这里是否是这种情况,因为您没有提到您使用的特定函数(库)。文件操作在大多数系统上都是同步的,所以不应该是问题。
    3. 从您所写的关于“信息的10字节部分”的内容来看,显式锁定似乎是不必要的(除非2没有强加它)。p1产生数据量。当准备读取数据时,p1通知p2(通过事件;无论如何,事件传递应该在内部同步)。p2知道它可以读取数据量,然后需要等待后续通知。可能会在处理前一个通知之前发送后续通知。因此,事件需要以某种方式排队。您还可以使用信号量而不是事件通知。
        2
  •  0
  •   anon    17 年前

    你需要读者获得一个锁-事件的使用是不可替代的。没有它,作者就可以在读卡器代码的任何位置开始写作。

        3
  •  0
  •   Jim Mischel    17 年前

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

    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队列,并且您取决于消费者处理数据的速度比生产者创建数据的速度快。如果你能 保证 那样的行为,你就没事了。否则,消费者将不得不跟踪它最后一次读取的位置,以便知道下一次应该读取的位置。

        4
  •  0
  •   Carlos A. Ibarra    17 年前
    1. 如果编写器可以在任何时候开始编写,那么就需要在读卡器中锁定互斥体。确保互斥体是命名的,以便p2可以打开它。

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

    在读者中,你可能需要寻找你点击EOF的地方,然后才能再次阅读。

    如果您确定写入程序总是在追加,并且可以知道记录的结束位置(例如,它们总是10个字节),并且可以接受一个小的延迟,并且写入程序总是写入完整的记录,那么您可以在不使用互斥和事件的情况下完成此操作。用fileshare.readwrite打开文件,在读卡器中,继续寻找同一个位置并尝试读取您的记录,如果无法读取,则睡眠一秒钟。如果您能够读取整个记录,则会得到一个。找出你的位置,然后回过头去寻找那个地方,然后再读一遍。这就是tail-f在UNIX中的工作方式。

        5
  •  0
  •   jpalecek    17 年前

    除了正常的同步功能外,您还可以使用 file change notification 在Windows上等待文件更改的API。