应用程序监视更改

时间:2011-12-04 08:31:06

标签: c# multithreading algorithm

我正在编写一个用于监控的GUI应用程序,我想就它的逻辑提供一些建议。基本上所有应用程序需要做的是每x分钟连接一个远程服务器,检查是否有更改,如果有更改,请对它们进行操作(更新本地数据库等等,具体取决于更改)。

我的第一个想法是:

  1. 有一个复选框(监控开/关)。点击(如果选中)启动计时器。
  2. Timer在其Tick方法中启动BackgroundWorker。
  3. DoWork方法执行连接/检索信息
  4. a)在WorkDone处理程序方法中从后台工作程序获取信息并使用它进行本地更新 b)在WorkDone处理程序方法上,根据获得的更改触发一个或多个自定义事件“SomethingChanged”; EventListeners从那里处理本地更新。
  5. 我的主要问题是从Timer调用Worker,因为我将Worker添加到Form中,现在它们位于不同的线程上(这是正确的描述吗?)然后传递结果是一个类似的问题。我正在阅读有关代表的内容,但仍不确定何时以及如何使用,以及首先是否真的有必要。我需要bgWorker和Timer吗?我是否需要自定义事件,或者我可以使用Switch(结果)在workDone中完成所有工作吗?这个一般原则首先是好的,也许有更好的东西,我正在重新发明轮子?提前谢谢!

3 个答案:

答案 0 :(得分:2)

从架构的角度来看:

消息队列可以解耦应用程序的各个位。您可以在Windows窗体应用程序中依赖Windows为您创建和管理的消息队列。 Google for PostMessage / GetMessage等。这通常称为“消息传递”。

典型的Arcitecture

  • 您应用的一部分将请求“推送”到队列中
  • 您应用的其他部分会从队列中“提取”请求并将结果写入第二个队列。
  • 然后,第一部分可以从第二个“结果”队列中“拉出”请求并显示给用户。

所以它看起来像这样:

App - >请求队列 - >处理引擎 - >结果队列 - >应用

处理引擎可以在同一个应用程序中,在同一个线程上,也可以在不同的线程/进程中(甚至是不同的机器)。

您可以使用简单队列:说Queue<string>()(只要您使用锁来访问它)或增加复杂性或更复杂/更多功能的队列。

天真战略和其他解决方案的问题......要考虑的事情:

  1. 如果您在旧请求尚未完成时提出新请求会怎样?
  2. 如果发生错误会怎样?你想要内联错误吗?您可以使用其他队列进行错误吗?
  3. 你想重试吗?
  4. 如果邮件丢失会怎样? (即请求被推送,但没有响应......)?有交易队列等。
  5. 示例代码

        object oLock = new object();
        Queue<string> requests = new Queue<string>();
        Queue<string> responses = new Queue<string>();
        Thread mThread;
        AutoResetEvent mEvent = new AutoResetEvent(false);
    
        public Form1()
        {
            InitializeComponent();
            mThread = new Thread(ProcessingEngine);
            mThread.IsBackground = true;
            mThread.Start();
        }
    
        private void ProcessingEngine()
        {
            string result;
            string request = null;
    
            while (true)
            {
                try
                {
                    mEvent.WaitOne();
    
                    lock (oLock)
                    {
                        request = requests.Dequeue();
                    }
    
                    var wc = new WebClient();
                    result = wc.DownloadString(request);
    
                    lock (oLock)
                    {
                        responses.Enqueue(result);
                    }
                }
                catch (Exception ex)
                {
                    lock (oLock)
                    {
                        responses.Enqueue(ex.ToString());
                    }
                }
            }
        }
    
    
        private void timer1_Tick(object sender, EventArgs e)
        {
            lock (oLock)
            {
                //Stick in a new request
                requests.Enqueue("http://yahoo.com");
    
                //Allow thread to start work
                mEvent.Set();
    
                //Check if a response has arrived
                if (responses.Any())
                {
                    var result = responses.Dequeue();
                    listBox1.Items.Add(result.Substring(1,200));
                }
            }
        }
    }
    

答案 1 :(得分:0)

如果您使用System.Windows.Forms.Timer代替System.Threading.Timer,您的Tick处理程序将从Form的消息循环中调用,您将拥有对所有控件的完全访问权限 - 可以安全地调用bgWorker.RunWorkerAsync()。至于检索结果 - 也可以从消息循环线程中调用RunWorkerCompleted,您可以在这里安全地更新您的UI。

答案 2 :(得分:0)

解决方案很简单 - INVOKE回到主线程。这是winform控件上的Invoke方法。这基本上会将执行线程更改为UI线程,并允许您操作UI。

这样做“阻止”(即每次控制一次,但有新闻时一次)。