看到线程未正确结束

时间:2016-07-22 07:58:10

标签: c# wpf multithreading

我正在使用C#和WPF在Visual Studio 2015上开发一个项目。有时我使用close命令退出运行项目,有时使用stop debug按钮退出。问题是经过几次测试后,我的电脑开始变热,风扇发出噪音。我必须退出Visual Studio才能让机器平静下来。

所以我有疑问:

  • 如何在测试后看到线程没有结束?
  • 当我了解它们时,如何正确地结束它们? (当Dispose
  • 时,我实际上是WindowClosing个线程
  • 当我使用stop debug按钮时,如何确保线程正确结束?

谢谢

编辑:

有任务管理器的屏幕截图。当我开始应用时,CPU从5%上升到15%(或事件25%)。 RAM从4GO上升到4.5。 当我停止应用程序时,CPU会在几秒内达到45%并返回到5%但RAM会变为4.70GO并且不会再下降。

task manager

EDIT2:

我在我的应用程序中创建了这种线程:

private bool isClosing = false;
public void Start()
{
    isClosing = false;
    ThreadPool.QueueUserWorkItem(new WaitCallback(doWorkThread));
}

public void Stop()
{
    isClosing = true;
}

private AutoResetEvent endPoolStateButton = new AutoResetEvent(false);
private void doWorkThread(object sender)
{
    Action action = new Action(() => doWork());
    while (!isClosing)
    {
        Thread.Sleep(100);
        this.Dispatcher.BeginInvoke(action, System.Windows.Threading.DispatcherPriority.Background);
    }
    endPoolStateButton.Set();
}

private void doWork()
{
    /* Job performed */
}

我想知道是否有一个非常好的方法来使用线程?如果应用程序关闭但未设置isClosing = true,则永远不会停止。线程永远不会真正中止?你认为这种线程会导致我遇到的所有麻烦吗?

2 个答案:

答案 0 :(得分:0)

这是my solution如何以优雅的方式停止线程。希望代码清楚。我使用CancellationToken来取消线程和ManualResetEvent中的操作以等待线程取消:

namespace ElegantThreadWork
{
    using System;
    using System.Threading;
    using System.Diagnostics;

    class ThreadObject
    {
        public CancellationToken CancellationToken { get; private set; }
        public ManualResetEvent WaitHandle { get; private set; }

        public ThreadObject(CancellationToken ct, ManualResetEvent wh)
        {
            CancellationToken = ct;
            WaitHandle = wh;
        }
    }
    public class Program
    {
        static void DoWork(CancellationToken ct)
        {
            Console.WriteLine("Thread[{0}] started", Thread.CurrentThread.ManagedThreadId);
            int i = 0;
            // Check for cancellation on each iteration
            while (!ct.IsCancellationRequested)
            {
                // Do something
                Console.WriteLine("Thread[{0}]: {1}", Thread.CurrentThread.ManagedThreadId, i);
                // Wait on CancellationToken. If cancel be called, WaitOne() will immediatly return control!
                // You can see it by elapsed time
                ct.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
                i++;
            }
            Console.WriteLine("Thread[{0}] has been cancelled", Thread.CurrentThread.ManagedThreadId);
        }
        static void ThreadProc(object state)
        {
            ThreadObject to = (ThreadObject)state;
            try
            {
                DoWork(to.CancellationToken);
            }
            finally
            {
                to.WaitHandle.Set();
            }
        }
        public static void Main(string[] args)
        {
            TimeSpan MAX_THREAD_EXITING_TIMEOUT = TimeSpan.FromSeconds(5);

            // Use for elegant thread exiting
            ManualResetEvent isThreadExitedEvent = new ManualResetEvent(false);
            CancellationTokenSource cts = new CancellationTokenSource();
            ThreadObject threadObj = new ThreadObject(cts.Token, isThreadExitedEvent);

            // Create thread
            Thread thread = new Thread(ThreadProc, 0);
            thread.Start(threadObj);

            Console.WriteLine("Just do something in main thread");

            Console.WriteLine("Bla.");
            Thread.Sleep(1000);

            Console.WriteLine("Bla..");
            Thread.Sleep(1000);

            Console.WriteLine("Bla...");
            Thread.Sleep(1000);

            Console.WriteLine("Thread cancelattion...");
            Stopwatch sw = Stopwatch.StartNew();
            // Cancel thread
            cts.Cancel();

            // Wait for thread exiting
            var isOk = isThreadExitedEvent.WaitOne(MAX_THREAD_EXITING_TIMEOUT);
            sw.Stop();
            Console.WriteLine("Waiting {0} for thread exiting. Wait result: {1}. Cancelled in {2}", MAX_THREAD_EXITING_TIMEOUT, isOk, sw.Elapsed);

            // If we couldn't stop thread in elegant way, just abort it
            if (!isOk)
                thread.Abort();
        }
    }
}

答案 1 :(得分:-1)

也许您可以尝试使用“Process Hacker”工具观察流程和线程的行为。使用此工具可以获得有关线程的更多详细信息,还可以检测deamon线程。

另一种方法可能是:尝试获取主进程的所有子线程并执行类似

的操作
Thread t1; // specific child thread 
t1.join();