如何实现跨平台的异步文件写入?

5
我正在创建一个程序,该程序将从远程机器接收消息,并需要将这些消息写入磁盘文件。我遇到的困难在于,该程序的目的是测试接收消息的库的性能,因此我需要确保将消息写入磁盘不会影响库的性能。该库通过回调函数将消息传递给程序。另一个困难是解决方案必须是平台无关的。
我有哪些选项?
我考虑了以下几点:
  • 使用boost:asio写入文件,但是似乎(请参见this文档),异步写入文件在该库的Windows特定部分中 - 因此无法使用。
  • 使用boost::interprocess创建消息队列,但是this documentation指出有三种方法可以发送消息,并且所有方法都需要程序阻塞(隐式或不隐式)如果消息队列已满,则我不能冒这个风险。
  • 创建一个std::deque<MESSAGES>从回调函数中将消息推入双端队列中,并在写入文件时弹出消息(在单独的线程上),但是STL容器not guaranteed to be thread-safe。我可以锁定推到和弹出双端队列,但我们正在谈论连续消息之间的47微秒,因此我想完全避免锁定。

有没有更多关于可能解决方案的想法?


消息之间的47微秒是指哪些消息?这是远程机器的节奏吗? - Pavel Zdenek
2个回答

2

boost::thread是跨平台的,因此您应该能够利用它创建线程来执行阻塞写操作。为了避免每次将消息放入主线程时都需要锁定容器,您可以利用双缓冲技术的修改,创建嵌套容器,例如:

std::deque<std::deque<MESSAGES> >

仅当准备添加消息的deque队列已满时,才锁定顶级deque队列。 写入线程将依次只锁定顶级deque队列,以弹出一个装满要写入的消息的deque队列。


2

STL容器可能不是线程安全的,但我从未遇到过不能在不同线程上的不同时间使用的容器。将所有权传递给另一个线程似乎是安全的。

我已经多次使用了以下方法,所以我知道它有效:

  • 创建指向std :: vector的指针。
  • 创建一个互斥锁来保护vector指针。
  • 使用new []创建std :: vector,然后为其保留(reserve)大尺寸。

在接收线程中:

  • 每当向队列添加项目时,请锁定互斥锁。这应该是一个短暂的锁。
  • 添加队列项。
  • 释放锁定。
  • 如果您感觉需要,则发出条件变量信号。我有时不会:这取决于设计。如果体积非常大且接收方没有暂停,则跳过条件并进行轮询。

在使用者线程(磁盘写入器)上:

  • 通过轮询或等待条件变量来查找要执行的工作:
  • 锁定队列互斥锁。
  • 查看队列长度。
  • 如果队列中有工作,请将指针分配给使用者线程中的变量。
  • 使用new []和reserve()创建一个新的队列向量并将其分配给队列指针。
  • 解锁互斥锁。
  • 去写你的项目到磁盘上。
  • 删除已使用的队列向量。

现在,根据您的问题,您可能需要一种阻塞的方法。例如,在我的一个程序中,如果队列长度达到100,000个项目,生产线程只需开始睡眠1秒并大声抱怨。这是不应该发生的事情之一,但确实会发生,因此您应该考虑它。如果完全没有限制,它将仅使用机器上的所有内存,然后崩溃并出现异常,被OOM杀死或在交换风暴中停止。


我刚刚看了另一个答案。如果每个项目的锁定成本太高,您也可以将其适应该要求。只需保留一个向量指针的向量,并在完成对其的写入时将向量添加到其中即可。 - Zan Lynx
另外需要注意的是:这种设计在Linux上运行得非常好,因为互斥锁使用futexes,当没有竞争时成本非常低。在BSD或Windows上使用CriticalSection也不错。但由于您想要实现跨平台性,嵌套容器锁定可能真的是最好的选择。 - Zan Lynx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接