我想要一个具有以下要求的FIFO队列:
我使用了这样的BlockingCollection
:
public LoggerReal()
{
main = (frmMain)Application.OpenForms[0];
LogQueue = new BlockingCollection<logEntry>(GlobalSettings.LogQueueSize);
Task.Run(() => {
foreach (logEntry LE in LogQueue.GetConsumingEnumerable()) {
try {
ProcessLogEntry(LE);
} catch (Exception E) {
functions.Logger.log("Error processing logEntry" + E.Message, "LOGPROCESSING", LOGLEVEL.ERROR);
functions.printException(E);
}
}
functions.Logger.log("Exiting Queue Task", "LOGPROCESSING", LOGLEVEL.ERROR);
});
}
但是,我注意到日志似乎只在队列已满时显示。
ProcessLogEntry
函数只是将它们放入ListBox
。
我尝试使用简单的队列而没有运气。
据我所知,ConcurrentQueue和其他Queue可能无法满足这些要求,或者我错了?我将队列处理器启动到一个任务中,这样它就可以永远等待,这不是问题,但只要数据可用就需要开始处理。
答案 0 :(得分:0)
你的标题有点令人困惑(FIFO是一个队列,根据定义,阻塞集合会等待/阻塞?)。但是,我会猜到你想要的东西......
我假设你想要2个线程,一个正在添加到队列(编写器),另一个被阻止/等待处理项目一旦被添加(读者)
创建阻止集合:
var dataSink = new BlockingCollection<logEntry]>(new ConcurrentQueue<logEntry>());
作家&#39;线程只是添加并继续它的方式
dataSink.Add(logEntryToAdd); // Add to collection and continue
读者&#39;线程阻塞,直到项目添加到队列
while (dataSink.Count > 0)
{
ProcessLogEntry(dataSink.Take());
}
我不确定你的溢出&#34; X&#34;但也许在“添加”期间操作你可以得到计数,如果它超过&#39; x&#39;要么不要添加或出列第一项(取决于你的逻辑流程需要什么)。
显然,确保UI线程没有被阻止(UI线程不应该是&#39;阅读器&#39;,如果需要,创建第三个线程,阻止/从队列中读取,然后通过UI通知UI调用以更新列表框)否则您的UI将无法响应......
答案 1 :(得分:0)
如果我理解了您的要求,您可以使用常规Queue<T>
基于Monitor
的简单信令,如下所示:
<强>成员:强>
private readonly int maxSize;
private readonly Queue<logEntry> logQueue;
private bool stopRequest;
构造
maxSize = GlobalSettings.LogQueueSize;
logQueue = new Queue<logEntry>(maxSize);
制作人方法:
public void Add(logEntry logEntry)
{
lock (logQueue)
{
if (stopRequest) return;
logQueue.Enqueue(logEntry);
if (logQueue.Count == 1)
Monitor.Pulse(logQueue);
}
}
停止流程工作者的方法:
public void Stop()
{
lock (logQueue)
{
if (stopRequest) return;
stopRequest = true;
Monitor.Pulse(logQueue);
}
}
流程工作者(使用Task.Run
调用的方法):
private void ProcessWorker()
{
while (true)
{
logEntry LE;
lock (logQueue)
{
while (!stopRequest && logQueue.Count == 0)
Monitor.Wait(logQueue);
if (stopRequest) break;
if (logQueue.Count > maxSize)
{
logQueue.Clear();
continue;
}
LE = logQueue.Dequeue();
}
try
{
ProcessLogEntry(LE);
}
catch (Exception E)
{
functions.Logger.log("Error processing logEntry" + E.Message, "LOGPROCESSING", LOGLEVEL.ERROR);
functions.printException(E);
}
}
functions.Logger.log("Exiting Queue Task", "LOGPROCESSING", LOGLEVEL.ERROR);
}
这只是为了得到这个想法,您可以进一步调整实施以更好地满足您的需求。
答案 2 :(得分:0)
所以最后我使用了BlockingCollection,但我使用tryTake而不是使用ConsumingEnumerable进行while循环:
Task.Run(() => {
while (!LogQueue.IsCompleted) {
logEntry LE;
LogQueue.TryTake(out LE, Timeout.Infinite);
try {
ProcessLogEntry(LE);
} finally {
// Do nothing, because if logging cause issue, logging exception is likely to do so as well...
}
}
//functions.Logger.log("Exiting Queue Task", "LOGPROCESSING", LOGLEVEL.ERROR); // Will not work if exiting Q
});