1

我正在尝试做一个 Windows 应用程序,我有一个需要几分钟才能完成任务的功能。我有一个开始按钮,我想添加一个停止按钮,以便在我想停止该功能时停止它的处理。

我正在尝试使用下面的代码,但我不确定如何在 btnStop 中中止 Thread1,因为 Thread1 被标记为“在当前上下文中不存在”。

请你建议我/指出我正确的方向,这将是一个很好的方法。提前致谢。

namespace SampleStartStop
{    
    public partial class Form1 : Form
    {        
        public Form1()
        {
            InitializeComponent();            
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Thread Thread1 = new Thread(SlowFunction);            
            Thread1.Start();                        
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            Thread1.Abort();
            MessageBox.Show("Processing canceled");
        }
        public void SlowFunction()
        {
            var end = DateTime.Now + TimeSpan.FromSeconds(10);
            while (DateTime.Now < end)
            { }
            MessageBox.Show("Process finished");
        }

    }
}

更新: 您好 KCdod,感谢您的帮助,当我仅将线程声明为全局变量时,我得到“SampleStartStop.exe 中发生了“System.NullReferenceException”类型的未处理异常”。

嗨阿列克谢,感谢您的更正。感谢 zerkms 和 Alexei 分享有关取消令牌的信息。按照您共享的链接中的示例,我能够编写下面的代码。它似乎有效,但如果它需要一些改变或者它是否可以,我希望你们专家的认可。

关于当前代码的唯一疑问是,如果按下停止按钮,它会停止处理正常,但是如果我再次单击开始按钮,什么也不会发生,我需要关闭并再次打开应用程序才能再次开始按钮,是这正常吗?

另一个疑问是在“听者”里面的部分。在 MSDN 示例中,他们输入“// Perform cleanup if necessary.”,那么,他们在谈论什么样的清理?

public partial class Form1 : Form
{       
    public Form1()
    {
        InitializeComponent();            
    }
    // Create the token source.
    CancellationTokenSource cts = new CancellationTokenSource();

    private void btnStart_Click(object sender, EventArgs e)
    {
        // Pass the token to the cancelable operation.
        ThreadPool.QueueUserWorkItem(new WaitCallback(SlowFunction), cts.Token);                       
    }

    private void btnStop_Click(object sender, EventArgs e)
    {
        // Request cancellation.
        cts.Cancel();
        // Cancellation should have happened, so call Dispose.
        cts.Dispose();

        MessageBox.Show("Processing canceled");
    }
    public void SlowFunction(object obj)
    {
        CancellationToken token = (CancellationToken)obj;

        var end = DateTime.Now + TimeSpan.FromSeconds(10);
        while (DateTime.Now < end)
        {
            // Thread 2: The listener 
            if (token.IsCancellationRequested)
            {
                // Perform cleanup if necessary. 
                //... 
                // Terminate the operation.                  
                break;
            }
        }
        if (!token.IsCancellationRequested)
        {
            MessageBox.Show("Processing finished");
        }
    }

}

更新: 感谢 Alexei 的更正,我已经根据您的建议修改了代码,这次效果很好。代码如下。我只有一个问题,因为在我的真实代码中,函数需要一个字符串参数才能工作,我不知道如何在“WaitCallback(SlowFunction)”部分中调用它以及如何在代码中定义函数,因为这里像这样定义“public void SlowFunction(object obj) {...}”,在我的真实函数中就像这样“public void SlowFunction(string str)”。我认为我需要在这个问题上提出一个新问题。

namespace SampleStartStop
{    
    public partial class Form1 : Form
    {       
        // Create the token source.
        CancellationTokenSource cts = new CancellationTokenSource();

        public Form1()
        {
            InitializeComponent();            
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }           
            // Pass the token to the cancelable operation.
            cts = new CancellationTokenSource();
            ThreadPool.QueueUserWorkItem(new WaitCallback(SlowFunction), cts.Token);                         
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
                cts = null;
                MessageBox.Show("Processing canceled");
            }   
        }
        public void SlowFunction(object obj)
        {
            CancellationToken token = (CancellationToken)obj;

            var end = DateTime.Now + TimeSpan.FromSeconds(5);
            while (DateTime.Now < end)
            {
                if (token.IsCancellationRequested)
                {                
                    break;
                }
            }
            if (!token.IsCancellationRequested)
            {
                MessageBox.Show("Processing finished");
            }
        }

    }
}
4

2 回答 2

4

没有好的方法可以终止不合作的线程。IndeedThread.Abort会这样做,但代价是可能会留下未处理的对象和废弃的同步原语,从而可能会破坏您的程序的稳定性。

解决您的直接问题 -Thread1成为类级别成员而不是局部变量。您需要检查它是否已设置/清除:

public partial class Form1 : Form {
   ...

  Thread thread1 = null;            

  private void btnStart_Click(object sender, EventArgs e)
  {
    if (thread1 != null)
    {
         thread1.Abort();
    }
    thread1 = new Thread(SlowFunction);            
    Thread1.Start();                        
  }

  private void btnStop_Click(object sender, EventArgs e)
  {
    if (thread1 != null)
    {
         thread1.Abort();
         thread1 = null;
         MessageBox.Show("Processing canceled");
    }
}

如果您可以使“慢功能”在终止中进行合作会更好 - 即通过定期检查一些值。检查取消令牌以了解 .Net 这样做的方式。

于 2015-01-06T03:23:28.550 回答
1

您可以将线程声明Thread Thread1;为全局变量。在您当前的代码中,您的Thread1范围限制为 btnStart_Click()事件功能。

namespace SampleStartStop
{    
    public partial class Form1 : Form
    {   
        Thread Thread1=null;
        public Form1()
        {
            InitializeComponent();            
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Thread1 = new Thread(SlowFunction);            
            Thread1.Start();                        
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            Thread1.Abort();
            MessageBox.Show("Processing canceled");
        }
        public void SlowFunction()
        {
            var end = DateTime.Now + TimeSpan.FromSeconds(10);
            while (DateTime.Now < end)
            { }
            MessageBox.Show("Process finished");
        }

    }
}

附加- 线程中止不是很好,但您可以使用它。

于 2015-01-06T03:17:15.087 回答