3

当用户单击运行时,应用程序会运行大量代码以生成模型并将其显示在图表中。跑步大约需要 1-2 分钟。我还有一个取消按钮,在单击“运行”按钮后启用。我正在使用 DotSpatial,因此我的按钮位于功能区 UI 的插件面板上。插件中Run和Cancel上的click事件启动,调用后端类的代码Run和Click。

当用户在运行开始后点击取消时,有一个延迟,但取消方法被调用并执行,但运行从未停止,我们最终看到图表显示。所以,我想我需要一个单独的线程来运行。我对编程相当陌生,从未使用过线程。我已经查看并添加了以下代码,但我的线程方法没有运行。这是我的代码:

单击运行按钮:

这是在顶部:

//check to see if RunModel thread needs to stop or continue
private volatile bool stopRun = false;
private Thread runThread;

然后这是从 click 事件中调用的方法:

public void btnRun_testingThread(object sender, EventArgs e)
{
   //create a new thread to run the RunModel
   if (runThread == null)
   { 
       //we don't want to stop this thread
       stopRun = false;

       runThread = new Thread(RunModel);  
       runThread.Start();              <--this isn't doing anything
   }

所以,我认为当代码到达 runThread.Start() 时,它会跳转到我的 RunModel 方法并开始运行代码。但事实并非如此。此外,我想取消这个线程(一旦我让它正常工作),所以我有这个,它从取消点击方法中调用:

private void StopRunThread()
{
    if (runThread != null)
    {
        //we want to stop the thread
        stopRun = true;
        //gracefully pause until the thread exits
        runThread.Join();
        runThread = null;
    }
}

然后这是我偶尔检查的 RunModel() 以查看 stopRun 布尔值是否已更改。

public void RunModel()
{
    ...some code.....

    //check to see if cancel was clicked
    if (stopRun)
    {
        ....clean up code....
        return;
    }

    ....some more code....

    //check to see if cancel was clicked
    if (stopRun)
    {
      ....clean up code....
       return;
    }
}

以及取消按钮的点击方法:

public void btnCancel_Click(Object sender, EventArgs e)
{
    stopRun = true;
    StopRunThread();
    //the model run has been canceled

    ....some code.....
}

对让 thread.start 实际运行 Run 方法有任何帮助吗?那么我是否需要不断检查运行中的 volatile bool 以便在停止时清理所有内容?谢谢!

4

2 回答 2

3

我认为你最好看看 BackgroundWorker - 这基本上是单独运行的,但可以注意取消命令。确保在初始化时添加“WorkerSupportCancellation”:

BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); // This does the job ...
backgroundWorker1.WorkerSupportsCancellation = true; // This allows cancellation.

然后单击即可开始您的过程:

public void btnRun_testingThread(object sender, EventArgs e)
{
   backgroundWorker1.RunWorkerAsync();
}

您的取消按钮可以发出取消请求:

public void btnCancel_Click(Object sender, EventArgs e)
{
    backgroundWorker1.CancelAsync();
}

然后,您的工作人员可以在工作时对此进行监控...

void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        if (backgroundWorker1.CancellationPending)
        {
            break;
        }
        else
        {
            // Do whatever you're doing.
        }
    }
    e.Result = backgroundWorker1.CancellationPending ? null : orders;
}

您可以通过添加进度条等来进一步增强这一点,但这会变得有点复杂,所以我不会在这里讨论。

于 2012-07-20T14:43:00.367 回答
0

考虑到推荐中提供的新信息,我相信您只是RunModel()因为对thread.Start()方法行为的错误假设而错过了调试器中方法的开始。

请参阅 MSDN 的注释,Thread.Start 方法

一旦线程处于 ThreadState.Running 状态,操作系统就可以调度它执行。线程从提供给线程构造函数的 ThreadStart 或 ParameterizedThreadStart 委托表示的方法的第一行开始执行。

线程启动需要一些时间的小演示,对我来说它在 38-40 毫秒内开始:

Stopwatch watch = new Stopwatch();
Thread thread = new Thread((ThreadStart)watch.Stop);
thread.Start();
watch.Start();

Thread.Sleep(5000);
double startedAfter = watch.ElapsedMilliseconds;

由于 .NET Framework 4.0 考虑使用 TPL 任务而不是显式使用线程,一些优点:

  • 您可以通过传入TaskUI 线程同步上下文轻松地与 UI 线程同步
  • 您可以使用轻松停止 TaksCancellationToken
于 2012-07-20T14:26:02.950 回答