2014-01-06 127 views
1

我想实现一个快速记录器,它包含日志条目,并且当某个触发器到达时,它将刷新最后的X条消息。我可以“强制”线程唤醒吗?

这样的想法是保持在一个循环缓冲区中的所有消息,一旦我们有触发,推它的ID到队列中,而另一线程监视(在所有系统中的一个线程)。此线程将返回X消息并刷新它们。我知道如何处理在我尝试刷新时正在写入的消息,在刷新正在刷新的消息之前已被覆盖的消息,而我试图更新它们等。

我的问题是,例如我有20个线程写消息,只有10个内核,在2个“writer”线程执行之间的时间差,所有的缓冲区都会被覆盖好几次。

有没有什么办法可以让“我的”线程“强制”“编写器”线程执行(或给它是时间片?我猜不,但是仍然... 你能建议任何其他方式/设计来克服这个问题

+1

取决于,但一次有多个线程写入硬盘驱动器会在硬盘驱动器达到饱和CPU处理速度之前很久就会饱和硬盘驱动器的速度。为了简单起见,我只有一个写线程: - /。在任何一种情况下,互斥锁或文件锁将有助于确保只有1(fifo)线程可以访问缓冲区或写入位置。 – IdeaHat

+0

@MadScienceDreams:是的,我有一个作家(相应地更新了问题)。但问题仍然存在,笔者有机会刷新它 – yosim

+0

可以给该线程优先级更高,所以只要用信号(通过条件变量之前缓冲区被覆盖,互斥,信号量,读者,作家锁,无论你想要什么),系统调度程序将执行该线程。请注意,您的问题可以通过更好的设计得到更好的解决。如果你的缓冲区在没有你的控制的情况下被覆盖,那么你需要重新思考你的日志机制。 – Shahbaz

回答

0

我写过类似的东西,其中对日志方法的调用实际上被放置在另一个线程(T-Logger)监视的队列中,这样就可以让其他线程不必调用底层日志的API和低延迟的应用效果很好。

如果你想明确地缓冲,然后触发写那么我还是建议你从做所有的写操作Ë线,如T-Logger然后用某种conditional variable来通知T-Logger,它现在应该去写在队列中的项目的基本日志文件。

正如问题评论中提到的,您应该避免让多个线程尝试执行IO操作。 IO非常慢,并且让所有线程试图写入文件都会导致它们放弃CPU周期等待IO完成。

+0

@Shahbaz - 真。我稍微改了一下我的答案。 – Sean

+0

是的,我将只有一个线程正在写入。主要问题是,条件变量是否确保线程一旦发出信号就会唤醒?我没能找到这样的保证(虽然有可能我没看够深...) – yosim

+0

@yosim - 条件变量将导致正在等待它转变为“可运行”状态的任何线程,在某些时候,操作系统会在CPU上安排线程并运行它。你永远不会得到一个解决方案,这将导致等待线程立即开始运行,因为操作系统将不得不考虑所有线程的调度。 – Sean

1

据我所知,只要队列中有新的ID可用,您就想恢复您的线程。这可能会导致锁定原语 - 您的编写器线程应该睡眠,直到触发器线程通知为止。如何实现这种行为取决于你正在使用的多线程框架。

例如,在C++ 11中,您可以看看std::condition_variable

编辑。正如评论中所提到的,磁盘IO速度很慢,所以您需要在写入程序线程中将消息提取到内存,然后才将它们写入磁盘。在IO期间,缓冲区可以被到达的消息覆盖。

+0

信号是否是当前睡在一个条件的线程,gaurantees它会醒来?我试过用互斥体,它没有工作,我想的条件,但我没能找到这样的保证。 – yosim

+0

条件变量专门旨在处理这种情况,所以该线程将醒来!事实上,即使[假的唤醒,(http://www.cplusplus.com/reference/ condition_variable /湿ition_variable/wait /)是可能的一些实现。有可能通过互斥体实现条件,但互斥体主要用于“互斥”。 –

0

听起来像使用信号量的经典案例,使用循环缓冲区的长度进行初始化。来自需要记录东西的线程的日志调用在继续之前必须从信号中获取一个单元,并且当日志线程从队列中提取一个条目时,该线程会通知信号量。如果缓冲区用完,任何尝试登录的线程都会阻塞,直到有足够的日志条目空间。

显然,对于日志条目的循环缓冲器/队列/不管容器必须是线程安全的。

+0

没有信号量,你可以达到同样的效果。只保留你刷新的最后一个索引,如果你的下一个索引是这个索引 - 你应该在缓冲区满时阻塞/做其他的事情。 但是,这有两个主要缺陷:1,记录器不能阻塞。但更重要的是,并非所有消息都需要刷新。很有可能我们几乎没有闪动的手倒立,然后冲洗一切。 – yosim