Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我需要在递归算法期间停止执行_C#_Multithreading_Recursion - Fatal编程技术网

C# 我需要在递归算法期间停止执行

C# 我需要在递归算法期间停止执行,c#,multithreading,recursion,C#,Multithreading,Recursion,我在选择正确的方法来实现我的目标方面遇到了问题。 我在做算法教学系统,我在用C。我需要将我的算法分成几个步骤,每个步骤都包含一个递归。 我必须在每个步骤后停止执行,然后用户可以使用GUI中的按钮移动到下一个步骤(下一个递归) 搜索后,线程是正确的选择,但我发现了几种方法: (线程。睡眠/中断):没有工作,我的GUI冻结了 (暂停/恢复):我读到使用它是个坏主意 (Waithandles):还在读关于他们的书 (监视等待/恢复) 我没有太多的时间来尝试和阅读所有以前的方法,请帮助我选择最适合我

我在选择正确的方法来实现我的目标方面遇到了问题。 我在做算法教学系统,我在用C。我需要将我的算法分成几个步骤,每个步骤都包含一个递归。 我必须在每个步骤后停止执行,然后用户可以使用GUI中的按钮移动到下一个步骤(下一个递归)

搜索后,线程是正确的选择,但我发现了几种方法:

  • (线程。睡眠/中断):没有工作,我的GUI冻结了

  • (暂停/恢复):我读到使用它是个坏主意

  • (Waithandles):还在读关于他们的书

  • (监视等待/恢复)


我没有太多的时间来尝试和阅读所有以前的方法,请帮助我选择最适合我的系统的方法。任何建议都非常欢迎

如果您想在用户界面继续交互的情况下“在后台”工作,或者如果您想将一个缓慢的任务拆分为多个处理器核,则只需要使用线程

您所描述的内容听起来好像只需要编写一个线程:

  • 记住用户在序列中的位置
  • 每次他们点击你的按钮,执行下一步

如果您希望使用线程,那么您可以使用AutoResetEvent来允许线程循环执行这些步骤,并在每次迭代中等待一个。然后,每当用户单击按钮开始下一步时,您的用户界面就会发出该事件的信号。(您还需要在步骤完成时通知UI,以便用户只能按顺序运行这些步骤,因为您可以在开始步骤时设置button.Enabled=false,而线程可以在完成步骤时使用button.Invoke来设置Enabled=true)。但是,对于您所描述的内容,线程听起来过于复杂。

您列出的所有内容都将阻止执行,如果在主线程中执行代码,则会冻结UI

如果您只需要挂起操作,然后恢复操作或取消操作,那么您必须将计算移动到单独的线程中,以便冻结它不会影响UI


你也可以从不同的角度来处理你的问题。您可以重新设计算法,以便可以从任意点重新启动它们-将递归堆栈设置为外部并将其作为参数传递

只要您使用正确的方法,线程都是好的。我想说,从以下步骤开始:

  • 创建一个带有两个按钮和两个s(例如b1、b2、p1、p2)的表单
  • 单击按钮b1时,在中启动递归算法1,并显示进度条p1中的进度。如果禁止用户按其他按钮很重要,则可以禁用这些按钮,直到p1完成
  • 当用户单击p2中的按钮b1时

  • 可能会有帮助。

    您正使用waithandles朝着正确的方向前进


    尝试使用。我认为这是一种实现目标的方法。

    从根本上说,这个问题并不是关于递归或多线程的,它只是这样:

    如何在GUI应用程序的后台执行长时间运行的操作,使应用程序保持响应

    实现您自己的线程模型是而不是,特别是当您刚刚开始学习多线程/异步操作时。NET Framework已经有了一个组件来完成您想要做的事情:,它可以在Winforms和WPF(以及几乎任何其他体系结构)中工作

    使用
    BackgroundWorker
    可以非常非常轻松地完成您想要的任务。在这个例子中,我将假设Winforms,但这是一个简单的例子

    显然,您还必须连接
    dowwork
    RunWorkerCompleted
    事件,并确保在
    BackgroundWorker
    上将
    worker支持扫描单元设置为
    true
    。之后,使用以下命令运行操作:

    bwRecursive.RunWorkerAsync(someTreeNode);
    
    并通过以下方式取消:

    bwRecursive.CancelAsync();
    

    这里唯一的问题是,您说您希望在每个“步骤”之后暂停(而不是停止)执行。我可能会使用一个
    自动resetEvent
    ,它是一种事件类型,每次等待成功时都会重置其信号(“就绪”)状态。同样,只需集成几行代码:

    public class MyForm : Form
    {
        private AutoResetEvent continueEvent = new AutoResetEvent(false);
    
        // Previous BackgroundWorker code would go here
    
        private void ExecuteRecursiveOperation(MyTreeNode node)
        {
            if (bwRecursive.CancellationPending)
                return;
    
            foreach (MyTreeNode childNode in node.ChildNodes)
            {
                continueEvent.WaitOne();  // <--- This is the new code
    
                if (bwRecursive.CancellationPending)
                    break;
    
                ExecuteRecursiveOperation(childNode);
            }
        }
    
        private void btnContinue_Click(object sender, EventArgs e)
        {
            continueEvent.Set();
        }
    
        private void btnCancel_Click(object sender, EventArgs e)
        {
            bwRecursive.CancelAsync();
            continueEvent.Set();
        }
    
        private void btnStart_Click(object sender, EventArgs e)
        {
            continueEvent.Set();
            bwRecursive.RunWorkerAsync(...);
        }
    }
    
    公共类MyForm:Form
    {
    私有自动恢复事件continueEvent=新自动恢复事件(false);
    //以前的BackgroundWorker代码将放在这里
    私有void ExecuteCursiveOperation(MyTreeNode节点)
    {
    if(bwRecursive.CancellationPending)
    返回;
    foreach(node.ChildNodes中的MyTreeNode childNode)
    {
    
    continueEvent.WaitOne()如果您对递归教学感兴趣,同时允许算法在每次迭代中暂停,您可能需要考虑创建一个状态管理器类,它封装算法并公开一个显式堆栈。递归算法实际上是一种基于堆栈的算法,因此能够运行单个迭代并查看。堆栈的内容将有助于演示递归实际上是如何运行的。我可以想象如下:

    public struct AlgorithmParameters
    {
        public readonly int Parameter1;
        public readonly int Parameter2;
    
        public AlgorithmParameters(int parameter1, int parameter2)
        {
            Parameter1 = parameter1;
            Parameter2 = parameter2;
        }
    }
    
    public class RecursiveAlgorithm
    {
        private Stack<AlgorithmParameters> _parameterStack = new Stack<AlgorithmParameters>();
    
        public IEnumerable<AlgorithmParameters> ParameterStack
        {
            get { return _parameterStack; }
        }
    
        public IEnumerable<RecursiveAlgorithm> RunAlgorithm(int parameter1, int parameter2)
        {
            return RunAlgorithm(new AlgorithmParameters(parameter1, parameter2));
        }
    
        public IEnumerable<RecursiveAlgorithm> RunAlgorithm(AlgorithmParameters parameters)
        {
            //Push parameters onto the stack
            _parameterStack.Push(parameters);
    
            //Return the current state of the algorithm before we start running
            yield return this;
    
            //Now execute the algorithm and return subsequent states
            foreach (var state in Execute())
                yield return state;
        }
    
        private IEnumerable<RecursiveAlgorithm> Execute()
        {
            //Get the parameters for this recursive call
            var parameters = _parameterStack.Pop();
    
            //Some algorithm implementation here...
    
            //If the algorithm calls itself, do this:
            int newParameter1 = 2; //Parameters determined above...
            int newParameter2 = 5;
            foreach (var state in RunAlgorithm(newParameter1, newParameter2))
                yield return state;
    
            //More implementation here...
    
            //We've finished one recursive call, so return the current state
            yield return this;
        }
    }
    
    公共结构算法参数
    {
    公共只读int参数1;
    公共只读int参数2;
    公共算法参数(int参数1、int参数2)
    {
    参数1=参数1;
    参数2=参数2;
    }
    }
    公共类递归算法
    {
    私有堆栈_参数堆栈=新堆栈();
    公共IEnumerable参数堆栈
    {
    获取{return\u parameterStack;}
    }
    公共IEnumerable运行算法(int参数1、int参数2)
    {
    返回RunAlgorithm(新算法参数(参数1,参数2));
    }
    公共IEnumerable运行算法(AlgorithmParameters)
    {
    //将参数推送到堆栈上
    _参数堆栈
    
    public struct AlgorithmParameters
    {
        public readonly int Parameter1;
        public readonly int Parameter2;
    
        public AlgorithmParameters(int parameter1, int parameter2)
        {
            Parameter1 = parameter1;
            Parameter2 = parameter2;
        }
    }
    
    public class RecursiveAlgorithm
    {
        private Stack<AlgorithmParameters> _parameterStack = new Stack<AlgorithmParameters>();
    
        public IEnumerable<AlgorithmParameters> ParameterStack
        {
            get { return _parameterStack; }
        }
    
        public IEnumerable<RecursiveAlgorithm> RunAlgorithm(int parameter1, int parameter2)
        {
            return RunAlgorithm(new AlgorithmParameters(parameter1, parameter2));
        }
    
        public IEnumerable<RecursiveAlgorithm> RunAlgorithm(AlgorithmParameters parameters)
        {
            //Push parameters onto the stack
            _parameterStack.Push(parameters);
    
            //Return the current state of the algorithm before we start running
            yield return this;
    
            //Now execute the algorithm and return subsequent states
            foreach (var state in Execute())
                yield return state;
        }
    
        private IEnumerable<RecursiveAlgorithm> Execute()
        {
            //Get the parameters for this recursive call
            var parameters = _parameterStack.Pop();
    
            //Some algorithm implementation here...
    
            //If the algorithm calls itself, do this:
            int newParameter1 = 2; //Parameters determined above...
            int newParameter2 = 5;
            foreach (var state in RunAlgorithm(newParameter1, newParameter2))
                yield return state;
    
            //More implementation here...
    
            //We've finished one recursive call, so return the current state
            yield return this;
        }
    }
    
    class MainWnd : Form{
        /*
         * A typical recursive factorial function would be
         * implemented something like this:
         */
        double Factorial(int n){
            return (double)n * Factorial(n - 1);
        }
    
        /*
         * Alternatively, factorial can be implemented iteratively:
         */
        double Factorial(int n){
            double product = n;
            while(--n > 1)
                product *= n;
            return product;
        }
    
        /*
         * Let's break the logic up into steps, so that it
         * saves its state between steps and resumes where
         * it left off for the next step.
         */
    
        int    factorialN;
        double factorialProduct;
    
        void BeginSteppedFactorial(int n){
            factorialProduct = n;
            factorialN       = n - 1;
        }
        bool StepFactorial(){
            if(factorialN <= 1)
                return true; // we're done, the result is ready
    
            factorialProduct *= factorialN--;
            return false; // we're not yet done, call the next step
        }
        double GetSteppedFactorialResult(){return factorialProduct;}
    
    
        static void Main(){Application.Run(new MainWnd());}
        MainWnd(){
            BeginSteppedFactorial(32);
    
            Label lbl = new Label(){
                AutoSize = true,
                Location = new Point(10, 10),
                Text     = GetSteppedFactorialResult().ToString(),
                Parent   = this
            };
            Button btn = new Button(){
                Location = new Point(10, 30),
                Text     = "Next Step",
                Parent   = this
            };
            btn.Click += (s, e)=>{
                if(StepFactorial()){
                   btn.Text = "Finished";
                   btn.Enabled = false;
                }
                lbl.Text = GetSteppedFactorialResult().ToString();
            };
        }
    }