我有一个问题我正在尝试决定如何处理和解决它,我有一个应用程序,用户选择某些文件,并且需要将文件添加到我的ListView
但在我需要检查这些文件之前(通过另一个类),我的问题是要知道这个操作完成以便更新我的GUI
请看这堂课:
public class ProducerConsumer : IDisposable
{
public delegate void OnFileAddDelegate(string file);
public event OnFileAddDelegate OnFileAddEventHandler;
BlockingCollection<string> _taskQ = new BlockingCollection<string>();
public ProducerConsumer(int workerCount)
{
// Create and start a separate Task for each consumer:
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew(Consumer);
}
public void Dispose()
{
_taskQ.CompleteAdding();
}
public void Enqueue(string action)
{
_taskQ.Add(action);
}
private void Consumer()
{
// This sequence that we’re enumerating will block when no elements
// are available and will end when CompleteAdding is called.
FileChecker fileChecker = new FileChecker();
foreach (string item in _taskQ.GetConsumingEnumerable())
{
string file = item;
string result = fileChecker.Check(file);
if (result != null && OnFileAddEventHandler != null)
OnFileAddEventHandler(result);
}
}
}
我在Winforms
应用程序中使用此类,在用户选择需要添加到我的ListView
的文件后,此类将此文件(PDF文件)放入Queue
并且使用者获取此文件并使用另一个类(FileChecker)检查每个文件(简单搜索),如果文件正常,则向主表单引发Event
以添加文件。
现在,当搜索/添加此文件时,我锁定了所有控制器,在此操作结束时,我想要解锁此控制器,但我不知道该类完成它的工作的具体时刻,我尝试放置break-point
在Consumer foreach loop
的末尾,但它似乎没有到达那里,所以我想知道我怎么知道这个操作何时完成
更新:
这是主要形式:
string[] files // All the files that the user choose
ProducerConsumer producerConsumer = new ProducerConsumer(5);
producerConsumer.OnFileAddEventHandler += pq_OnFileAddEventHandler;
foreach (string item in files)
{
string filename = item;
producerConsumer.Enqueue(filename);
}
答案 0 :(得分:2)
如果你真的想要产生它们并在它们完成时杀死它们,那么 你不应该使用阻塞队列,而是使用同步的正常队列:
public class ProducerConsumer {
public delegate void FileAddedDelegate(string file);
public delegate void AllFilesProcessedDelegate();
public event FileAddedDelegate FileAdded;
public event AllFilesProcessedDelegate AllFilesProcessed
readonly Queue<string> queue; int counter;
public ProducerConsumer(int workerCount, IEnumerable<string> list) {
queue = new Queue<string>(list); // fill the queue
counter = queue.Count; // set up counter
}
public void Start() {// split this to be able to add event hooks in between
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew(Consumer);
}
private void Consumer() {
FileChecker fileChecker = new FileChecker();
for(;;) {
string file;
lock(queue) { // synchronize on the queue
if (queue.Count == 0) return; // we are done
file = queue.Dequeue(); // get file name to process
} // release the lock to allow other consumers to access the queue
// do the job
string result = fileChecker.Check(file);
if (result != null && FileAdded != null)
FileAdded(result);
// decrement the counter
if(Interlocked.Decremet(counter) != 0)
continue; // not the last
// all done - we were the last
if(AllFilesProcessed != null)
AllFilesProcessed()
return;
}
}
}
注意:您的示例看起来像 idea ,而不是完整的代码。该解决方案专为自由运行的消费者而设计 - 当他们到达空闲队列时,他们正在等待工作和报告。
使用一些计数器:
int counter;
在排队文件之前增加它
Interlocked.Add(ref counter, files.length);
foreach (string item in files) {
string filename = item;
producerConsumer.Enqueue(filename); }
消费者减少和测试:
if (result != null) {
if(OnFileAddEventHandler != null)
OnFileAddEventHandler(result);
if(Interlocked.Decrement(ref counter) == 0
&& OnAllFilesProcessed != null)
OnAllFilesProcessed();