首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >按线程顺序同步访问固定大小队列的线程

按线程顺序同步访问固定大小队列的线程
EN

Stack Overflow用户
提问于 2012-11-08 07:52:09
回答 3查看 575关注 0票数 4

在一次采访中,我被问到以下问题:

有一个固定大小的任务队列。线程希望对任务进行排队。如果队列已满,则应等待。线程顺序应该保持不变:如果thread1与task1一起出现,而在此之后,thread2与task2一起出现,则task1应该在task2之前输入队列。

其他线程希望将任务排出队列并执行它。如果队列是空的,它们应该等待,它们的顺序也应该保持不变:如果t3位于t4之前,t3应该在t4之前对任务进行排队。

如何实现这一点(在伪代码中)?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-08 13:21:14

  1. .NET 4.0中的简单解决方案引入了命名空间System.Collections.Concurrent,其中的类工作得很好--我无法从它们那里获得一些错误。 ConcurrentQueueBlockingQueue是你开始研究的地方。但我认为你的问题不是关于标准解决方案的--这是面试的糟糕答案,所以:
  2. 基于杰弗里·里希特的书信息的解决方案: 基本代码(C#):内部密封类SynchronizedQueue {私有只读对象m_lock =新对象();私有只读队列m_queue =新队列();公共无效队列(T item) { Monitor.Enter(m_lock);//在排队后唤醒任何/所有服务员m_queue.Enqueue(项目);Monitor.PulseAll(m_lock);Monitor.Exit(m_lock);}公共T Dequeue() { Monitor.Enter(m_lock);//循环,当队列为空(条件)而(m_queue.Count == 0) Monitor.Wait(m_lock);//从队列中返回一个项,以处理T项= m_queue.Dequeue();Monitor.Exit(m_lock);返回项;}} 这个类是线程安全的,但仍然不检查订单,这里有很多实现方法。来自同一本书: ConcurrentQueueConcurrentStack都是无锁的;它们都在内部使用Interlocked方法来操作集合。

因此,您必须删除Monitor类的使用,并为您的线程作为下一个登记项提供检查。这可以通过在私有字段中保持当前加法器的数量、当前队列长度来实现。您应该将此字段设置为易失性

您应该使用Interlocked.Exchange获取当前加法器Interlocked.Read获取当前队列长度

在此之后,您的线程有唯一的编号-当前长度+当前加法器。使用SpinWait类旋转,而当前长度将不等于您的编号,在该队列项之后,并离开enqueue方法。

我强烈建议你学习这本书中关于多线程和锁的章节--在你的生活中,你会对这类问题做更多的准备。也尝试在这里搜索类似的问题。例如:

在.NET?

票数 0
EN

Stack Overflow用户

发布于 2012-11-08 10:09:14

要同步访问有限数量的资源,通常使用信号量。谷歌让它得到你自己的想法。

困难的部分是保持阻塞线程的顺序。

我在C#:http://dcutilities.codeplex.com中找到了一个包含一个http://dcutilities.codeplex.com的项目

票数 0
EN

Stack Overflow用户

发布于 2012-11-08 10:17:25

如果生产者线程正在等待numEmptySpaces信号量来访问队列,这种行为可能无论如何都会发生,因为信号量等待队列在FIFO之外的任何实现都是不合理的,但在大多数信号量实现中不能保证这样做。

保证这种行为是非常尴尬的,因为很难定义‘线程顺序’的要求:

如何定义哪个线程最先到达?

如果‘第一个线程’获得了某种类型的锁,从而阻止其他线程继续运行,那么后续的线程就会“立即”进入,因此必须服从操作系统提供的任何锁队列顺序。

我唯一能想到的就是强迫每个生产者线程在试图锁定/排队之前获得一个无锁的时间戳或序列号。这可以通过“正常”原子增量指令来完成。当生产者随后通过获取“numEmptySpaces”单元“进入”并锁定队列时,它可以按序列号顺序将自己排队到队列上。

我不确定是否可以使用标准的BlockingCollection。您可能能够按序列号“OrderBy”条目,但我不确定这个操作是否锁定了队列-它应该可以,但是..。此外,必须将sequenceNo作为私有备忘录添加到BlockingCollection后代中,并将原子增量结果维护为每个任务的状态--您必须将其添加到Task成员中。

我很想通过自己的BlockingQueue类构建一个“正常”队列、耦合信号量和一个互斥体来实现这一点,一旦获得了numEmptySpaces单元和队列互斥体,就按序列号顺序向队列中插入新任务。然后可以将原子增量结果组装到堆栈/auto var中。

这可能是一个面试问题,但我必须受到解雇的威胁,才能在生产代码中实际执行。很难想象在什么情况下它可能是必要的。额外开销和争论的负面影响超过了我所能想到的一切值得怀疑的好处。

对于试图在dequeue/execute端显式维护任何类型的排序,我也有类似的保留意见。试图确保按序号顺序到达脱队列任务中的“检查点”将是一件很麻烦的事情。它需要任务的合作,任务需要私有同步对象成员在到达检查点时发出信号。永远不要尝试:)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13284730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档