C# WPF工作线程需要使用者通知暂停

C# WPF工作线程需要使用者通知暂停,c#,wpf,worker,worker-thread,C#,Wpf,Worker,Worker Thread,嗨,我有一个生产者-消费者模式。WPF UI是长时间运行的工作线程的一种辅助工具,该线程正在侦听数据包和请求任务。在实践中,所有消息都将退出队列,然后UI使用者进行处理 我的问题是我有一个UIcontroller类,它负责所有WPF GUI组件。它将打开一个新窗口,显示每个出列的任务,并保存一个线程安全的引用窗口集合 我用调度员发信号。开始呼叫。这并不奇怪 我遇到的问题是,如果UIController类成功打开配置数量的窗口,我希望挂起/实际停止我的工作线程。打开的窗口数量有限制。一旦打开的窗口

嗨,我有一个生产者-消费者模式。WPF UI是长时间运行的工作线程的一种辅助工具,该线程正在侦听数据包和请求任务。在实践中,所有消息都将退出队列,然后UI使用者进行处理

我的问题是我有一个UIcontroller类,它负责所有WPF GUI组件。它将打开一个新窗口,显示每个出列的任务,并保存一个线程安全的引用窗口集合

我用调度员发信号。开始呼叫。这并不奇怪

我遇到的问题是,如果UIController类成功打开配置数量的窗口,我希望挂起/实际停止我的工作线程。打开的窗口数量有限制。一旦打开的窗口数量在限制范围内减少,我将继续处理队列。我尝试将我的窗口集合保存在这个类中,并通过调用将其传递给UI,在该调用中它通过引用进行更新,但Begin调用是异步的,并且计数在工作线程的循环中没有及时更新

我可以测试UIcontroller类中打开的窗口的数量,忽略甚至从那里重新查询任务-基本上不采取任何行动。但我想要一个更干净的解决方案

我能做些清洁的回拨吗

    public void Work()
    {

        while (true)
        {

            Log.Instance.Info("****In worker THREAD " + _worker.Name);

            while (_controller.IncomingMessages.Count > 0 && [--test for no of windows open on GU thread somehow - I did try holding a reference to the collection in this class--])
            {
                try
                {
                    Log.Instance.Info("****In Notification worker THREAD and messages to process " + _worker.Name);

                    Messages.AlertMessage task = null;
                    lock (_locker)
                    {

                        if (_controller.IncomingMessages.Count > 0 && ToasterPopUps.Count < 5)
                        {
                            task = _controller.IncomingMessages.Dequeue();
                            if (task == null)
                            {
                                return;
                            }
                        }

                        if (task != null)
                        {
                            Log.Instance.Info("Dequeing: " + task + " " + task.ID + " from Notification thread");

                _UIthread.BeginInvoke(DispatcherPriority.Background, new JoinUIThread(DespatchUIThread), task, _UIthread);
                        }
                    }

                }
                catch (Exception err)
                {
                    Log.Instance.Critical(string.Format("Unexpected Error in PollPopUp Thread Queue {0} ", err));
                }

            }

            Log.Instance.Info("No more Notification tasks - wait for a signal");

            _wh.WaitOne();

        }

    }

    public void DespatchUIThread(Messages.AlertMessage task, System.Windows.Threading.Dispatcher dispatcherThread)
    {
        try
        {
            _controller.CreateWindow(task, dispatcherThread);
        }
        catch (Exception err)
        {
            Log.Instance.Critical("Critical error " + err);
        }
    }

如果我理解您的意思,您希望生产者线程在UI窗口数达到某个阈值时等待。我将使用生产者和消费者共享的信号量,并初始化为max window count来完成此行为

const int MaxWindowCount = 5;
Sempahore semaphore = new Semaphore(0, MaxWindowCount );
在每次排队之前,你都要先打电话

semaphore.WaitOne();
一旦每个任务完成并且窗口关闭,调用

semaphore.Release();
MaxWindowCount项目进入队列后,制作人将等待下一次调用WaitOne,并等待调用Release

嗯,这可能无法实现您想要的,因为它将队列中的项目数限制为MaxWindowCount,而不一定是打开的窗口数。它假设排队中的每个项目都有一个打开的窗口,但在您的情况下可能不是这样

如果这是一个无效的假设,您可以有一个线程负责从队列中提取项目。此线程将负责在将项目传递给UIController时调用WaitOne。UIController仍然负责调用Release。实际上,您将有两个生产者-消费者队列。一个用于任务的无界队列和一个用于windows的有界队列

-2010年5月21日增补-

另一个选项可能是让对CreateWindow的调用采用回调参数,告诉控制器打开的窗口数

使用以下委托作为CreateWindow的参数,可以保持Worker中打开窗口的计数,并在达到最大值时采取相应措施

public delegate void CreateWindowCallback( int numOpenWindows );
您可以在worker中记录打开的窗口数,并且需要让worker知道最大窗口数。或者,您可以在控制器类中保留CanOpenNewWindows布尔值

在调用_UIthread.BeginInvoke之前,工作者可以检查当前窗口计数或CanopenNewWindow属性,如果不应该打开新窗口,则调用WaitOne。当窗口关闭时,您仍然需要知道一些信息,以便释放/通知工作人员继续

如果窗口创建失败,或者控制器不需要显示窗口,您可以让工作人员知道打开的窗口计数没有增加。这确实假设_控制器知道是否创建了窗口

-另一种想法-

可以在UIController中保留所有窗口创建逻辑。UIController需要知道UIThread并修改CreateWindow调用以仅接受任务

如果打开的窗口少于最大值,则调用CreateWindowtask将调用BeginInvoke。否则,它将调用WaitOne并等待其中一个窗口发出关闭的信号。我们可以在这里使用一个信号量,在每次成功创建窗口后调用WaitOne。每个窗口将负责在关闭时调用Release


这样,当工作人员直接调用CreateWindow时,当达到最大窗口数时,它将阻塞,并且它永远不必知道最大窗口数或有关UI的许多其他信息。

感谢您的输入。问题是消费者可能无法打开窗口,或者决定不打开窗口。最后一个建议听起来不错。我不清楚这将如何工作,但我将有一个游戏。虽然我制定了有界和无界的解决方案,但我已经成功地将不需要的消息重新发送回队列。这有点混乱,因为我必须在构造函数中传递大量的类,以便UIcontroller可以看到我的队列。无论我做什么,我都需要重构。我出人意料的直截了当的解决方案是乐观地打开最大数量的窗口
通过调用UI控制器来调用。然后我等了一个。UIcontroller通过将计数重置为可用窗口数重新激活工作线程:每当一个或多个窗口关闭时。。。唯一的问题是,如果一个或多个窗口无法打开,我可能只打开一个窗口,而不是允许的最大值。如果全部无法打开,我可能会永久阻止。我可以在错误处理中处理这个问题。我意识到我在把想法吐出来。我想得越多,给这只猫剥皮的方法就越多。埃德-非常感谢。最后,我完全按照你的建议做了——请一位代表。我没有意识到你可以把委托作为一个参数——我需要重新阅读委托的用法!