最多包含 N 个线程的代码部分,按 FIFO 顺序执行
本文关键字:FIFO 执行 顺序 代码部 包含 线程 | 更新日期: 2023-09-27 18:37:23
我有一段代码,应该由最大数量的线程执行,线程调用someFunction()的顺序应该反映在它们进入该部分的顺序中,即FIFO顺序。
如果我使用信号量,我无法控制线程进入该部分的顺序。
"没有保证的订单,例如FIFO或LIFO,其中被阻止 线程进入信号量。
最初的尝试:
class someClass
{
static volatile Semaphore semaphore;
...
someClass()
{
semaphore = new Semaphore(N,N)
}
someType someFunction(InputType input)
{
try
{
semaphore.WaitOne();
/* Section Begins */
var response = someHeavyJob(input); // submitted to the server
return response;
/* Section Ends */
}
finally
{
semaphore.Release();
}
}
}
如果我像下面这样组合信号灯和 ConcurrentQueue,线程可能会返回对其他线程带来的请求的响应,这将需要对代码的其他部分进行重大更改。针对以下问题的 .NET 4.5 解决方案是什么:
- 允许代码部分中的最大线程数小于 N
- 线程进入该部分的顺序是 FIFO 线程将获得它们带来的请求的响应
(而不是对其他线程带来的请求的响应)
class someClass { static volatile ConcurrentQueue<someType> cqueue; static volatile Semaphore semaphore; ... someClass() { cqueue = new ConcurrentQueue<someType>(); semaphore = new Semaphore(N,N) } someType someFunction(Request request) { try { cqueue.enqueue(request); semaphore.WaitOne(); Request newrequest; cqueue.TryDequeue(out newrequest); /* Section Begins */ var response = someHeavyJob(Request newrequest); // submitted to the server return response; /* Section Ends */ } finally { semaphore.Release(); } } }
更新:我正在澄清我的问题:SomeHeavyJobs() funciton 是对正在处理此作业的服务器的阻塞调用。
UPDATE2:谢谢大家的回答。郑重声明:我最终使用了FIFO信号量
"如果我像下面这样组合信号灯和 ConcurrentQueue,线程可能会返回对其他线程带来的请求的响应,这需要对代码的其他部分进行重大更改。
我不想这么说,但我建议"代码其他部分的更改",即使我不知道这会有多大的"意义"。
通常,如您所建议的那样,通过将包含对原始类实例的引用的消息排队来满足,以便可以将响应"返回"到请求它们的对象。 如果发起方都是某个"消息处理程序"类的后代,那么在将调用该函数的线程(应该是消息处理程序的成员)上会更容易。 线程执行函数后,它们可以调用消息处理程序的"onCompletion"方法。"onCompletion"可以发出发起方正在等待的事件的信号(同步),也可以将某些内容排队到发起方的私有 P-C 队列(异步)。
因此,一个 BlockingCollection、一个使用者线程和明智地使用 C++/C# 继承/多态性应该可以完成这项工作。
奇怪的是,这几乎正是我目前的嵌入式ARM项目被迫进入的。用于配置/调试/日志的命令行界面线程现在非常大,以至于即使在"拇指,优化大小"模式下,它也需要大量的 600 字堆栈。不能再允许它直接调用 SD 文件系统,现在必须将自身排队到运行 SD 卡的线程(该线程具有系统中运行 FAT32 的最大堆栈),并在信号灯上等待 SD 线程调用其方法并在完成后发出信号量信号。
这是确保按顺序进行调用并将正常工作的经典方法。 它基本上是一个只有一个线程的线程池。
就像其他海报所写的那样,任何其他方法都可能是,错误。"勇敢"。
线程调用 someFunction() 的顺序也应该是 反映在他们进入该部分的顺序上,即 先进先出订单
原则上这是不可能的。
semaphore.WaitOne(); //#1
var response = someHeavyJob(input); //#2
即使信号量是严格的FIFO,也可能发生以下情况:
- 所有线程按先进先出顺序进入该部分 (1)
- 所有线程都从 CPU 取消调度(介于 1 和 2 之间)
- 所有线程都以随机顺序甚至后进先出顺序(1 到 2 之间)重新调度
- 所有线程开始以任意顺序进入某个繁重作业 (2)
您永远无法确保线程将按特定顺序"进入"函数。
至于 FIFO 信号量,您可以使用锁和队列自己构建信号量。看起来您已经这样做并发布了代码。据我所知,这种方法是正确的。
你看过智能线程池吗?
[编辑]
如果我仍然正确解决问题,正如我在评论中所说,我不相信多线程解决方案对这个问题是可行的。
如果在任务 k-1 完成之前无法启动任务 k,则只需要一个线程即可执行它们。如果允许您并行执行某些任务组合,则需要准确指定规则。