0

今天我在 Windows 窗体应用程序中添加了多线程。在我的 UI 线程上,我正在通过 new Thread() {...}).Start(); 它本身将调用一个使用 ThreadPool.QueueUserWorkItem() 的方法。调用方法后,线程将在队列中等待,直到返回特定项目并退出线程:

new Thread(o =>
        {
            s.SimulateChanges();

            Boolean run = true;

            while (run)
            {
                SimulationResult sr = queue.WaitDequeue();

                //EOF is a static property which will be returned 
                //if the queue is at its end so I can break the while loop
                if (SimulationResult.EOF.Equals(sr))
                {
                    run = false;
                    continue;
                }

                this.simulationProgressBar.BeginInvoke((Action)delegate()
                {
                    if (sr.IsDummy && this.simulationProgressBar.Value < this.simulationProgressBar.Maximum)
                    {
                        /*...*/
                    }
                    else
                    {
                        this.resultListView.AddObject(sr);
                    }
                });
            }

            this.simulationProgressBar.BeginInvoke((Action)delegate()
            {
                this.ToggleSimulationControls(true);
            });
        }).Start();

这就是调用方法的代码:

public void SimulateChanges()
{
    ThreadPool.QueueUserWorkItem(o =>
        {
            foreach (IColElem elem in collection.AsEnumerable())
            {

                /*lot of code*/

                queue.Enqueue(new SimulationResult() { IsDummy = true });

            }
            log.Debug("Finished!");

            queue.Enqueue(SimulationResult.EOF);

        });
}

我的队列是一个自写的类,它允许线程等待出队,直到一个对象入队。

一切正常,除了如果我停止调试(使用停止调试或简单地关闭应用程序)我无法重建我的应用程序,因为 VS2010 不会删除文件句柄。我相信这与我的线程没有正确退出有关。他们有什么办法我可以保证吗?

感谢您的任何建议:-)

4

1 回答 1

1

很难解释问题的所有方面。但是你犯了一个很常见的错误,通常是程序员第一次开始使用线程时犯的。当用户关闭主窗口时,您不能确保线程停止运行。这是一个容易犯的错误,UI 线程处理了很多繁重的工作。包括在用户关闭应用程序的主窗口时自动终止。所以至少你的部分问题是你确实设法关闭了主窗口。但实际上并没有终止该过程。无法构建,您的程序的 EXE 仍在使用中。

正确关闭线程可能非常困难,因为无论线程在做什么,用户都会关闭窗口。它可能是紧张的,深埋在操作系统调用中并等待它完成。当它不执行代码时很难要求它退出。

有一个非常简单的解决方案,至少足以让您的项目继续进行或解决您遇到的一半问题。您可以将线程标记为“程序终止时自动终止”,CLR 会处理它。使用 IsBackground 属性,如下所示:

var t = new Thread(o =>
        {
           // Lotsa code
        });
t.IsBackground = true;
t.Start();

但请记住,这种杀戮没有什么优雅的。如果您正在编写文件或与服务器通信,那么这将导致部分写入的文件或非常混乱的服务器。否则与使用任务管理器杀死程序没有什么不同。

于 2013-04-15T17:16:55.347 回答