gpt4 book ai didi

c++ - 多线程访问的高效结构

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:00:07 25 4
gpt4 key购买 nike

我需要实现一种机制,该机制具有一个数据结构(此刻为队列),其中包含一个待处理的请求对象的列表,这些对象在使用时由不同的线程标记,在线程使用完该线程后将其删除。

在任何给定时间,此数据结构中最多可以包含数千个项目,并且N个线程将从中接收请求(本质上将其标记为“已接受”),然后当线程完成时,它将在结构中找到相同的请求,并且去掉它。

现在,我想知道C++ STL队列在执行此操作方面是否有效,以及在需要将其从队列中删除时是否必须再次查找同一项目?

我不希望这种数据结构被线程同步机制锁定太长时间,因为线程正在其中寻找某项。这可能会锁定我的整个程序。 (该程序必须具有很高的性能和速度)

谁能建议如何在多线程环境中最好地实现这一点,以使该结构在需要执行搜索时不会长时间锁定?

最佳答案

您可能正在关注什么不是您设计中最困难的部分。

如果队列是没有任何优先级的FIFO,那么您的访问器将是push_back()和pop_front()-即使您不麻烦使用比较交换(CAS)语义,但坚持使用a简单的互斥/关键部分。如果您需要对流量进行优先级排序的能力,则事情会变得更加艰难。如果您确实使用CAS锁定,那么(无论如何在Windows上)您都无法在boost::thread的shared_mutex上进行改进,而不会花费太多时间来进行这部分编码。不确定非Windows实现。

此问题最复杂的部分通常是发信号通知空闲的工作程序线程来接管新工作。在queue.front()为非空之前,您不能让它们循环,因此您需要一种方法来确保踢出正确数量的空闲线程来拾取排队的项目。当工作线程空闲时,它可以检查是否有新工作,如果不是,则执行,否则队列状态需要设置为空闲,以便下一个push_back导致“唤醒”踢,以重新启动工作线程池。该区域必须对所有非致命异常都具有100%的鲁棒性,否则您的流程将变得一片漆黑。

您是在管理自己的线程还是在使用内置线程池?您是否打算拥有一个动态大小的线程池,或者只是生成N个线程(可能是可配置的)并使它们运行直到进程退出?

绝对有工作线程执行工作项过程的日志记录。了解谁在其生命周期的任何阶段都拥有工作项至关重要。停止/开始工作,以及工作项摘要和时间安排将很有用。如果日志记录很慢,则通过即发即弃队列将其推送到单独的线程,但是您必须注意那里的延迟,这会降低日志的实用性。如果您确实需要从外部操纵进行中的工作项的能力,则从挂起的工作队列中选择一个单独的结构-通过线程索引并显示当前状态/开始时间并进行单独锁定的进行中的工作项,听起来是个好主意。此结构将是O(线程数),因此小于“待处理”队列,因此,如果长时间运行的结果操作在结构锁之外完成,则扫描它就不会成为瓶颈。

关于性能-您的工作线程将要做什么?如果工作项需要长期运行,执行大量I/O或其他昂贵的操作,那么队列交互并不是您的性能瓶颈,因此对该区域进行过度优化相对而言是无济于事的。在您的设计中考虑整个系统的性能,而不仅仅是一小部分。

这仅适合初学者。祝您好运,这不是一个易于健壮设计的系统。

[编辑]基于工作项描述。

解析应该很快(尽管可能涉及昂贵的源数据检索-很难说吗?),而数据库访问则要少一些。听起来,调优数据库可能是您在性能方面最大的收获。如果您对此无能为力,则只需要尽可能减少设计中的慢速DB。如果您可以选择执行异步数据库访问,则工作线程可以执行足够的工作来启动数据库调用,然后完成回调中的工作,从而允许在工作线程上启动其他工作。如果没有异步数据库访问,那么如果没有其他间接方法(您的主工作线程不等待数据库调用完成内联),将很难实现可靠的请求超时。您需要使主工作线程与对数据库的依赖脱钩,除非您可以信任数据库及时返回或出错。也许对数据库请求有一些可配置的或特定于工作项的超时? DB API库通常允许这样做。

您的超时监控器需要保持对工作项状态的了解。可能在您的工作项上使用一些虚拟的Cancel()方法,以确保灵活地清理超时项目。

关于c++ - 多线程访问的高效结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3634589/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com