【问题标题】:Conflicts in writing/reading a file写入/读取文件的冲突
【发布时间】:2015-06-26 07:44:54
【问题描述】:

我正在用 C 语言开发一个小软件,它可以在布告栏上读取和写入消息。每条消息都是一个以渐进式数字命名的 .txt。

该软件是多线程的,有很多用户可以进行并发操作。

用户可以进行的操作有:

  1. 阅读整个布告栏(所有 .txt 文件内容的串联)
  2. 添加消息(添加名为“id_max++.txt”的文件)
  3. 删除消息。删除消息后,该数字中将出现一个永远不会被填满的空洞(例如,“1.txt”、“2.txt”、“4.txt”)。

现在,我想知道是否有一些 I/O 问题 (*) 我应该管理(以及如何)或操作系统(类 Unix)自己解决所有问题。

(*) 比如2个用户想要读取和删除同一个文件

【问题讨论】:

  • 说真的,使用数据库,而不是文件系统。此外,您的描述并没有让我相信您应该使用多个线程。
  • 我知道使用 db 更简单,但在我的规范中是不允许的...
  • 程序员最重要的职责就是告诉比你更笨的人为什么规范是错误的。
  • 如果你想通过大学考试,那就不要了。该考试专门针对 C/Unix,与 DB 无关。
  • 然后失败。尝试执行此任务将违反道德规范。

标签: c multithreading file-io concurrency


【解决方案1】:

因为你有一个类 Unix,操作系统会在文件被另一个线程打开时删除它:目录条目被立即删除,文件本身(inode)在最后一次关闭时被删除。

我能看到的唯一问题是目录扫描和文件打开之间:竞争条件可能导致文件已被删除。

恕我直言,您必须考虑到错误文件不存在是正常的,然后直接转到下一个文件。

您描述的内容还不错,因为它类似于用于邮件的 MH 文件夹,并且即使涉及锁定,它也可以被许多不同的进程访问。但是根据负载和消息的大小,您可以考虑使用数据库。经验法则(我的意见):

  • 很少有并发访问和大文件:继续使用文件系统
  • 许多访问和小文件(最多几个):使用数据库

当然,在创建新消息时,您必须使用受互斥体保护的例程来查找下一个数字(应归功于@merlin2011 注意到问题)。

您在评论中说您的规范不允许使用数据库。与邮件处理类比,您也可以使用单个文件(如传统邮件格式):

  • 一个文件
  • 每条消息前面都有一个固定大小的标头,说明它是活动的还是已删除的
  • 读访问不需要同步
  • 写访问必须同步

这将是一个穷人的数据库,其中所有同步都手动完成,但是每个线程只有一个文件描述符并保存所有打开和关闭操作。在读取多而写入或删除少的情况下是有意义的

一个可能的改进是(仍然像邮件阅读器一样)建立一个包含每条消息的偏移量和状态的索引。根据您的要求,索引可以在磁盘上或内存中。

【讨论】:

    【解决方案2】:

    更简单的解决方案是使用像 sqlite 或 MySQL 这样的数据库,这两种数据库都提供了可以用来实现一致性的事务。如果您仍想继续前进,请继续阅读。

    问题不是 IO 问题,如果您没有实施适当的监视器,它是并发问题。考虑以下场景(它不是唯一有问题的场景,而是其中的一个示例)。

    1. 用户 1 读取最大 id 并将其存储在局部变量中。
    2. 同时,用户 2 读取相同的最大 id 并将其存储在本地变量中。
    3. 用户 1 先写入,然后用户 2 覆盖用户 1 刚刚写入的内容,因为它对最大 id 的概念相同。

    可以通过将当前最大 id 保持为在程序初始化时初始化的变量,并用锁保护 get_and_increment 操作来解决这种特殊情况。但是,如果您采用这种方法,这并不是您需要推理的唯一有问题的场景。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-15
      • 2013-12-12
      • 2015-04-10
      • 1970-01-01
      相关资源
      最近更新 更多