我有一段代码应该由低于N的最大线程数执行,并且线程调用someFunction()的顺序应该反映在它们进入该部分的顺序中,即FIFO订单。
如果我使用Semaphore,我无法控制线程进入该部分的顺序。
“没有保证订单,例如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();
}
}
}
如果我将Semaphore和ConcurrentQueue组合在一起,则以下线程可能会返回对其他线程带来的请求的响应,这需要对代码的其他部分进行重大更改。 什么是针对以下问题的.NET 4.5解决方案:
线程将获得他们带来的请求的响应(而不是其他线程对请求的响应)
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()函数是对正在处理此作业的服务器的阻塞调用。
UPDATE2: 谢谢大家的答案。为了记录:我最终使用了FIFO Semaphore
答案 0 :(得分:1)
你看过Smart Thread Pool吗?
<强> [编辑] 强>
如果我仍然正确地解决问题,正如我在评论中所说,我不相信多线程解决方案对于这个问题是可行的。
如果在 k-1 任务完成之前无法启动任务 k ,那么您只需要一个线程来执行它们。如果允许您并行执行某些任务组合,则需要准确指定规则。
答案 1 :(得分:1)
也应该是线程调用someFunction()的顺序 反映在他们进入该部分的顺序,即 FIFO订单
原则上这是不可能的。
semaphore.WaitOne(); //#1
var response = someHeavyJob(input); //#2
即使Semaphore是严格的FIFO,也可能发生以下情况:
您永远无法确保线程将按特定顺序“输入”该功能。
对于FIFO信号量,您可以使用锁和队列自己构建信号量。看起来你已经这样做并发布了代码。据我所知,这种方法是正确的。
答案 2 :(得分:1)
'如果我将Semaphore和ConcurrentQueue组合在一起,如下所示,线程可能会返回对其他线程提出的请求的响应,这需要对代码的其他部分进行重大更改。'
我讨厌这样说,但我会建议“代码的其他部分发生变化”,即使我不知道这会有多大“重要性”。
典型地,通过对包含对原始类实例的引用的消息进行排队,以便可以将响应“返回”到请求它们的对象,可以如您所建议的那样满足这样的要求。如果发起者都来自某个'messagehandler'类,那么这将使调用该函数的线程变得更容易(它应该是messagehandler的成员)。一旦线程执行了该函数,它们就可以调用messagehandler的'onCompletion'方法。 'onCompletion'可以发信号通知发起者正在等待的事件,(同步),或者将某些事件排队到发起者的私有P-C队列,(异步)。
因此,一个BlockingCollection,一个消费者线程和明智地使用C ++ / C#继承/多态应该可以完成这项工作。
奇怪的是,这几乎就是我当前嵌入式ARM项目所强加的内容。用于config / debug / log的命令行界面线程现在非常大,即使在“Thumb,Optimize of size”模式下,它也需要大量600字的堆栈。它不能再被允许直接调用SD文件系统,现在必须将自己排队到运行SD卡的线程(它在系统中具有运行FAT32的最大堆栈),并等待SD线程的信号量到调用它的方法并在完成后发出信号。
这是确保按顺序进行调用并确保工作的经典方法。它基本上是一个只有一个线程的线程池。
就像其他海报写的那样,任何其他方法都可能是,错误的......'勇敢'。