如何在C#中暂停和恢复循环 [英] How to pause and resume loops in C#

查看:98
本文介绍了如何在C#中暂停和恢复循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ex: -

Ex:-

for(int i=0;i <=10;i++)
{
Messagebox.show(i.ToString());

//*Here I want something like pause, so if I click Pause button of WinForms and consider i=4, then this loop must pause, until not going to click on Resume button.
And if now click on Resume button after 5-10 minutes then it should start from same state where we paused (from i=4) *//

//Why I am looking for this
I extract list of .sql files in a folder then open each .sql file and do some text extraction to extract table name, and then I create script with help of these tables names in a loop, file by file 

so I want a pause button in between of loop to see Original text, extract table name and further dynamically created text on Winforms, if required to check randomly. For which I am looking Pause/Resume functionality in a loop(I am using foreach loop)*//
}

//Actual Program

try
{
                
//using LINQ
StringBuilder result = new StringBuilder();
string connetionString = null;
foreach (XElement level1Element in XElement.Load(ManifestFile).Elements("Objects"))
{
if (level1Element.Attribute("AssetClass").Value.ToUpper() == "Common".ToUpper())
{ 
connetionString = System.Configuration.ConfigurationManager.AppSettings["UAT_EQ"].ToString();
}
cnn = new SqlConnection(connetionString);
cnn.Open();
CreateTempTable(cnn);
                    
result.AppendLine(level1Element.Attribute("AssetClass").Value);
foreach (XElement level2Element in level1Element.Elements("DeployObject"))
{
result.AppendLine("  " + level2Element.Value);
TxtReader(level1Element.Attribute("AssetClass").Value.ToString(),level2Element.Value.ToString(), string.Concat(string.Concat(fPath, level1Element.Attribute("AssetClass").Value), string.Concat("\\", level2Element.Value)), cnn);
Thread.Sleep(1000); //Here I am looking for Pause and Resume functionality
}
ExtractTableName(cnn);
CreateFile(cnn);
cnn.Close();
} 





请帮忙。



< b>我尝试了什么:



尝试谷歌并找到: -

暂停并恢复C#中的For循环 - 堆栈溢出 [ ^ ]

BackgroundWorker类(System.ComponentModel) [ ^ ]



但问题是backgroundWorker1.CancelAsync();不要暂停循环,它会停止循环,但我希望循环从我们暂停它的位置开始,点击Resume。



Please help on this.

What I have tried:

Tried google and found:-
Pause and Resume a For-Loop in C# - Stack Overflow[^]
BackgroundWorker Class (System.ComponentModel)[^]

But problem is backgroundWorker1.CancelAsync(); don't pause loop, it stops loop , but I want loop to start from that position where we paused it, on click of Resume.

推荐答案

我想出了这个想法:



I came up with this idea:

class Program
    {
        static volatile bool paused = false;
        static volatile bool finished = false;
        void PauseLoop()
        {
            for(int i=0; i<1e6;i++)
            {
                while (paused) { }
                Console.WriteLine(i);
            }
            finished = true;
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            ThreadStart ts = new ThreadStart(p.PauseLoop);
            Thread t = new Thread(ts);
            t.Start();

            char c;
            while(!finished)
            {
                if (Console.ReadKey().Key == ConsoleKey.P)
                    paused = true;
                else
                    paused = false;

                Console.WriteLine(paused ? "Pause" : "Resume");
            }

            Console.ReadKey(); // pause while testing

        }


定时器是一个很好的选择,以确保你不应该浪费资源,当你应该暂停时,比如你可以选择循环一些东西直到行动起来



Timers are a good alternative, to make sure you do not waste ressources when you're supposed to be pausing, like optionally if you instead were to loop something until called to action

using System;
using System.Threading;

namespace sandbox
{
    class PausableBase : IDisposable
    {
        private Timer _t;
        private bool _tickExecuting;

        public event EventHandler Tick;

        public PausableBase()
        {
            _t = new Timer(TimerTick, null, Timeout.Infinite, Timeout.Infinite);
        }

        private void OnTick(object sender, EventArgs e)
        {
            Tick?.Invoke(sender, e);
        }
        public void Pause()
        {
            _t.Change(Timeout.Infinite, Timeout.Infinite);
        }

        public void Resume()
        {
            _t.Change(0, 1000);
        }

        public void Start()
        {
            _t.Change(0, 1000);
        }

        private void TimerTick(object state)
        {
            if (_tickExecuting)
                return;
            _tickExecuting = true;
            try
            {
                OnTick(this, EventArgs.Empty);

            }
            catch (Exception ex)
            {
                //TODO: Something more sentient about exceptions occuring whilest invoking event delegate
            }
            finally
            {
                _tickExecuting = false;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected void Dispose(bool disposing)
        {
            if (!disposing)
                return;
            if (_t != null)
            {
                _t.Dispose();
                _t = null;
            }
        }
    }
}


在那里放一个信号量。然后从其他地方设置信号量。例如,一个通常为false的简单公共布尔属性。在上面的foreach循环中,如果布尔值为false,则代码正常进行。如果布尔值为true,则暂停。您可以将其实现为:



Put a semaphore in there. Then just set the semaphore from elsewhere. For example, a simple public boolean property that is normally false. In the foreach loop above, if the value of the boolean is false, then the code proceeds as normal. If the boolean is true, it pauses. You might implement this as:

foreach( XElement..... )
{
  //...
  while( this.Semaphore ) Thread.Sleep(5); // Pause is here when Semaphore == true
  //..
}





然后,在您想要暂停的位置,只需在信号暂停时设置信号量即可。例如,如果在标记为暂停的按钮上有事件处理程序,则在事件触发时,检查信号量。如果为false,则将其设置为true并将按钮文本更改为Resume。如果是,则将其更改为false并将按钮文本设置为Pause。这样的事情:





Then, where you want to pause, just set the semaphore when you want it paused. For example, if you have an event handler on a button labelled "Pause", when the event fires, check the semaphore. If it's false, then set it to true and change the button text to "Resume". If it's true, then change it to false and set the button text to "Pause". Something like this:

protected void MyButton_ClickEvent( object sender, EventArgs e)
{
   myThread.Semaphore = !myThread.Semaphore; // Toggle semaphore

   // Update button to reflect what it will do next
   if( myThread.Semaphore ) ( (Button)sender ).Text = "Resume";
   else ( (Button)sender ).Text = "Pause";
}





繁荣。问题解决了。如果你有一大堆线程,那么只需扩展这个想法。也许有一个运行带有复选框的线程列表,每个复选框都设置/清除该特定线程的信号量,这样您就可以随意暂停/恢复特定线程,或者只需一个按钮暂停/恢复所有内容。无论你需要什么。



Boom. Problem solved. If you have a whole bunch of threads, then just extend the idea. Maybe have a list of the threads running with checkboxes next to each that set/clear the semaphore for that particular thread so you can pause/resume specific threads at will, or just have one button pause/resume everything. Whatever you need.


这篇关于如何在C#中暂停和恢复循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆