【问题标题】:Starting and Stopping loop from thread c#从线程 c# 启动和停止循环
【发布时间】:2018-01-04 09:24:09
【问题描述】:

所以这是我需要解决的大问题。我有我的 Visual C# 应用程序。在此应用程序中,用户输入数据并单击执行。当他们单击执行时,核心方法在新线程中启动,在该线程和方法中是一个循环。不断使用方法调用程序,我向用户窗体发送循环实际执行的更新。例如像这样,我正在更新每条 cicle 中的 progressBar。

progressBar1.Invoke((MethodInvoker) delegate { progressBar1.Value += 1; });

我需要在 UserForm 中添加一个按钮,该按钮会停止该线程中的循环并显示已完成的操作。不退出应用程序不停止进程或者我只需要跳转到该线程并停止循环。

我正在考虑添加一个带有公共方法的公共类,称为 stop_loop.cs。我希望当我启动程序或在新线程中执行核心方法时它会跳转到该类并将取消设置为 = false,如果我单击停止按钮它也会跳转到该类并将取消设置为 true . 最后,在该线程中该循环中的每个 cicle 开始时,它将检查取消是否为真。如果是,则它将停止循环并移至执行结束。

像这样。不幸的是,我似乎无法从我的核心功能访问这个类。甚至 Visual Studio 都没有为我提供这个选项。我该怎么做 ?

namespace textboxes
{
    public class stop_loop
    {
        public bool is_canceled;

        public void set_canceled(bool state)
        {
            this.is_canceled = state;
        }
        public bool get_canceled()
        {
            return this.is_canceled;
        }
    }
}

【问题讨论】:

  • 你为什么需要一个单独的类呢?为什么不只是类中的一个成员变量来做这项工作?
  • 阅读 CancelationToken,听起来你正在做的是典型的用例
  • 检查ManualResetEvent类描述here
  • 请注意,您的代码看起来像 java 语法。您可以简单地定义一个属性:public bool IsCanceled {get; set; } 并删除该变量以及这两个 get 和 set 方法。只需将其设置为IsCanceled = true; 并使用var x = yourClass.IsCanceled; 获取它
  • 或许你可以利用break;上面提到的。

标签: c# multithreading


【解决方案1】:

您应该使用CancellationToken。这是一个计算阶乘的示例:

static void Main(string[] args)
{
    CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
    CancellationToken token = cancelTokenSource.Token;

    Task task1 = new Task(async () => await Factorial(5, token));
    task1.Start();

    Console.WriteLine("Type Y to break the loop:");
    string s = Console.ReadLine();
    if (s == "Y")
        cancelTokenSource.Cancel();

    Console.ReadLine();
}

static async Task Factorial(int x, CancellationToken token)
{
    int result = 1;
    for (int i = 1; i <= x; i++)
    {
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Canceled");
            return;
        }

        result *= i;
        Console.WriteLine("Factorial of {0} equals {1}", i, result);
    }
}

【讨论】:

  • 很好,我使用了这个并根据我的需要进行了调整。最后一件事是如何实现这个cancelTokenSource.Cancel();到用户窗体中的按钮,因为这不起作用。 private void button1_Click(object sender, EventArgs e) { cts.Cancel(); }
  • 我用简单的应用代码创建了gist
  • Aschchuk 非常感谢你这很好,但还有一件事,当我取消任务并重新启动它(我没有关闭整个应用程序)它从一开始就停止,就像令牌不是刷新或类似的东西。可能是什么原因?我应该在最后丢弃令牌还是什么?
  • 是的,您应该在cancelTokenSource.Cancel() 之后调用cancelTokenSource.Dispose() 并在void button1_Click 开始时重新创建令牌cancelTokenSource = new CancellationTokenSource()
  • 谢谢布拉德利!我重构了答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多