【问题标题】:Starting a new thread with a constructor使用构造函数启动新线程
【发布时间】:2012-03-14 12:58:21
【问题描述】:

我完成了一些繁重的小项目。我意识到在这么短的计算时间内,我的 GUI 冻结了。所以我做了一些研究,发现了这个 => http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUI

我开始实施这是我的项目,但我意识到这个特定的实施在我的项目中不起作用。

在我的项目中,我有许多类和一个控制所有其他类的“经理”。如果我初始化这个 Manager 类,它已经在构造函数中完成了繁重的工作。

我的问题:

如何使用构造函数启动新线程?

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
        {


            if (System.IO.File.Exists(e.FullPath) == true)
            {

                Manager mgr = new Manager(e, handreader); // here starts the heavy lifting
                Thread mgrThread = new Thread(new ThreadStart(mgr));  // what to do ?
                sl.Text = mgr.test();
                txtLog.Text = mgr.output();


            }
        }

编辑: 好吧,我决定重新编码我的程序。现在繁重的工作在一个功能中,但我认为我犯了一个错误。

整个程序如下所示:

 private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
        {


            if (System.IO.File.Exists(e.FullPath) == true)
            {
                Manager mgr = new Manager(e, handreader, txtLog, sl);
                //sl.Invoke(new MethodInvoker(mgr.test));
                sl.Invoke(new MethodInvoker(mgr.test)); // first try 
                Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try

            }
        }

sl.Invoke(new MethodInvoker(mgr.test)); // first try 工作,但它仍然冻结我的 GUI。

Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try

而这条线什么也不做。

我的测试功能:

 public void test()
    {
        StringBuilder builder = new StringBuilder();
        foreach (PlayerController pc in fm.lPc)
        {
          Range  range = new Range(handReader.hand, handReader.handversus, pc);
          builder.Append(pc.getHeroCardsSimple()+" vs 100% range =   "+range.vsRange()+"\r\n");
        }
        sl.Text = builder.ToString();
    }

【问题讨论】:

    标签: c# multithreading user-interface


    【解决方案1】:

    您应该为此使用不同的方法。您的构造函数仍在 GUI 线程上被调用。

       

        Func<Manager> asyncConstructor;
        private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
        {
            asyncConstructor = new Func<Manager>(() => new Manager());
    
            asyncConstructor.BeginInvoke(ManagerConstructed, null);
        }
    
        private void ManagerConstructed(IAsyncResult result)
        {
            Manager mgr = asyncConstructor.EndInvoke(result);
            //we can only access form controls from the GUI thread, 
            //if we are not on the gui thread then
            //do the changes on the gui thread.
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    sl.Text = mgr.test();
                    txtLog.Text = mgr.output();
                }));
            }
        }
    

    【讨论】:

    • 即使这回答了主要问题,我也同意 Jon 的观点:不要在构造函数中做繁重的工作!
    【解决方案2】:

    将“繁重的工作”从构造函数中移到某种“工人”并在线程中运行该方法。

    从以下位置更改经理:

    public Manager(/*params*/)
    {
        //params
        //heavy lifting
    }
    

    public Manager(/*params*/)
    {
        //params
    }
    
    public void DoWork()
    {
        //heavy lifting
    }
    

    和呼唤

    Manager mgr = new Manager(e, handreader);
    Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork));
    mgrThread.Start();
    

    注意:如果您在线程中访问/更改 UI 元素,请不要忘记调用该调用!

    【讨论】:

      【解决方案3】:

      嗯,你可以使用:

      Thread mgrThread = new Thread(() => new Manager(e, handreader));
      

      ...但是您的代码的其余部分将没有对管理器的引用。

      老实说,由于各种原因,在构造函数中进行繁重的工作通常是个坏主意。最好将这项工作转移到其他地方:

      // Constructor just sets things up
      Manager mgr = new Manager(e, handreader);
      // DoWork method does the real work
      Thread mgrThread = new Thread(mgr.DoWork);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-19
        • 1970-01-01
        • 1970-01-01
        • 2015-06-30
        相关资源
        最近更新 更多