StackQ Ответов: 3

Как приостановить и возобновить циклы в C#


Экс:-
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();
} 


Пожалуйста, помогите мне в этом.

Что я уже пробовал:

Попробовал Гугл и нашел:-
Приостановка и возобновление цикла For В C# - переполнение стека[^]
Класс BackgroundWorker (System.ComponentModel)[^]

Но проблема в backgroundWorker1. CancelAsync (); не приостанавливайте цикл, он останавливает цикл , но я хочу, чтобы цикл начинался с той позиции, где мы его приостановили, по щелчку Resume.

Philippe Mori

Сколько времени требуется для обработки одного элемента? При приостановке можно ли завершить текущий элемент? Сколько у вас предметов?

Эти детали важны для того, чтобы предложить лучшее решение, так как в противном случае мы можем только догадываться, но это может быть не лучшее решение.

Кстати, вы, вероятно, не хотите держать соединение открытым, находясь в состоянии паузы.

StackQ

// Почему я ищу это
Я извлекаю список файлов. sql из xml-файла, затем открываю каждый файл. sql и делаю некоторое извлечение текста, чтобы извлечь имя таблицы, а затем создаю необходимый скрипт с помощью этих извлеченных имен таблиц в цикле, один за другим

Обязательные ответы на вышеприведенный комментарий:-
- На обработку одного предмета вряд ли уйдет 1-2 секунды.
- Когда вы делаете паузу, не хотите ничего прерывать, просто хотите сделать паузу.(Предположим, у меня есть файл 10 .sql, в цикле, если i=5, значит, я обработал 5 файлов, теперь, если приостановлен, то он получит паузу,а если возобновится отсюда через 10-15 минут, то обработка должна начаться с i=6, значит, с 6-го файла)
- Сколько у вас элементов?> У меня есть xml-файл, где будет список файлов. sql, максимальное количество файлов. sql будет от 400 до 500

И да, я не хочу держать соединение открытым, находясь в состоянии паузы. Но это не будет проблемой,потому что это среда UAT, и все обрабатывается только с помощью глобальной временной таблицы и временных хранимых процедур. В базе данных нет никакого реального объекта.

3 Ответов

Рейтинг:
2

BacchusBeale

Мне пришла в голову такая идея:

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

        }


Рейтинг:
2

Thomas Nielsen - getCore

Таймеры-хорошая альтернатива, чтобы убедиться, что вы не тратите ресурсы впустую, когда вы должны делать паузу, например, если вместо этого вы должны были что-то зациклить до тех пор, пока вас не призовут к действию

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;
            }
        }
    }
}


Рейтинг:
1

YrthWyndAndFyre

Поставь туда семафор. Затем просто установите семафор из другого места. Например, простое общедоступное логическое свойство, которое обычно является ложным. В приведенном выше цикле foreach, если значение логического значения равно false, то код выполняется в обычном режиме. Если логическое значение истинно, оно приостанавливается. Вы можете реализовать это следующим образом:

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


Затем, когда вы хотите сделать паузу, просто установите семафор, когда вы хотите, чтобы он остановился. Например, если у вас есть обработчик событий на кнопке с надписью "пауза", когда событие срабатывает, проверьте семафор. Если это false, то установите его в true и измените текст кнопки на "Resume". Если это правда, то измените ее на ложь и установите текст кнопки на "пауза". Что-то вроде этого:

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";
}


Бум. Проблема решена. Если у вас есть целая куча нитей, то просто расширьте идею. Возможно, у вас есть список запущенных потоков с флажками рядом с каждым, которые устанавливают / очищают семафор для этого конкретного потока, чтобы вы могли приостановить/возобновить определенные потоки по своему желанию,или просто есть одна кнопка приостановить/возобновить все. Все, что тебе нужно.


StackQ

Во-первых, спасибо за ваше решение.
Я новичок в c#, поэтому не знаю, как работать с потоками, так как мой основной навык-SQL Server. Не могли бы вы помочь немного больше здесь, как объявить myThread и так далее?

Фактическая кнопка с которой я обрабатываю всю работу:-
частная btnNext_Click недействительным(объект отправителя, EventArgs в электронной)
{
Диалоговое окно openfiledialog ОПН = новое диалоговое окно openfiledialog();
ОПН.InitialDirectory = " C:\\";
ОПН.Filter = " xml-файлы (*. xml)|*. xml";
if (opn. ShowDialog()==DialogResult.ОК)
{
строку стр = ОПН.SafeFileName;
//строки стр = "C:\\TextReader\\";
XMLReaders(ОПН.Именем.Заменить (str,""), opn.Именем); //делаю свою работу, это определение выше на мой главный вопрос
}
}

Я хочу, чтобы цикл паузы/возобновления существовал в приведенной выше функции: - XMLReaders (), который запускался событием щелчка другой кнопки, отсюда (ниже события щелчка кнопки):-
частная btnPR_Click недействительным(объект отправителя, EventArgs в электронной)
{

}

Однако я пытаюсь реализовать ваше решение, но буду признателен за вашу помощь (мне будет легче :)