zatrzymanie pętli w głównej metodzie

0

witam po raz kolejny :]

tym razem mam pytanie po części teoretyczne :). Zastanawiam się jak spowodować wstrzymanie pętli głównej programu. Najprostrze rozwiązanie które przyszło mi do głowy to skorzystanie ze zmiennej bool pause. W oparciu o jej stan pętla głowna będzie kontynuowałą działanie:
while ( "...lista warunków..." && !pause)

pause zmienia swoją wartość w momencie naciśnięcia przycisku btnPause.

Program miałby następującą struktórę

namespace Program
{
    public partial class Form1 : Form
        {
           public bool pause = false;
           ...
           private void btnStart_Click(object sender, EventArgs e)
           {
                while ("...lista warunków..." && (!pause)) 
                {
                    ...
                }
           }

           private void btnPause_Click(object sender, EventArgs e)
           {
                if (simulationClock > 0)
                {
                    pause = !pause;
                }
           }
}

teraz zostaje jeszcze jeden problem.

Zagadnienie: pętla powinienna kontynuować działanie po 2krotnym wcisnięciu btnPause
Rozwiązanie: a) wprowadzić wątki
b) użyć przerwań (jeśli takowe są możliwe w C#)

Które z powyższych rozwiązań proponujecie?

0
namespace Program
{
    public partial class Form1 : Form
        {
           public bool pause = false;
           ...
           private void btnStart_Click(object sender, EventArgs e)
           {
                my_loop()
           }

           private void btnPause_Click(object sender, EventArgs e)
           {
                if (simulationClock > 0)
                {
                    pause = !pause;
                    if (!pause) my_loop();
                }
           }

           private void my_loop()
           {
                 while ("...lista warunków..." && (!pause)) 
                {
                    ...
                }
           }
}

takie cos ?

0

Tylko, ze kiedys nacisniejsz btnStart to juz nic wiecej w aplikacji nie wykonasz chyba ze w srodku jej bedziesz wykonywal Application.DoEvents() ale nie jest to ladne rozwiazanie (wrecz fatalne bym powiedzial).

Petle bys musial wystartowac w osobnym watku by to w miare sensownie dzialalo :)

0
wasiu napisał(a)

Petle bys musial wystartowac w osobnym watku by to w miare sensownie dzialalo :)

oczywiście :] nie ujolem tego w kodzie gdyz zastanawialem sie takze nad przerwaniem.

.k napisał(a)

takie cos ?
to tez jest rozwiazanie :] jednak watek, w tym przypadku, bedzie bardziej naturalnym rozwiazaniem :]

I ponawiam pytanie - czy przerwania sa obslugiwane w C#?

0

Ja bym radził się zapoznać z BackgroundWorker'em.

0

Zdefiniuj, co rozumiesz pod pojeciem przerwania... Jesli myslisz o czasach DOS'a, to chwyc jakas ksiazke z obecnego wieku i poczytaj troche. Cos podobnego moze osiagniesz komunikatami; jak pisalem, zalezy czym dla ciebie jest przerwanie: co je generuje i jakie ma znaczenie dla aplikacji...

0

Zdecydowałem się na wątek. Pętla while uruchamiana jest w nowym wątku. W niej następuje wykonanie zdarzen umieszczonych na liscie eventList. O eventList wspominalem tutaj

Jednakze pojawil sie problem. W petli korzystam z listBox'a - wyswietla on kolejne zdarzenia. Podczas debugowania wyskakuje błąd:

Nieprawidłowa operacja między wątkami: do formantu 'listBox' uzyskiwany jest dostęp z wątku innego niż wątek, w którym został utworzony.

Pseudokod program wygląda nastepujaco:

namespace Program
{
   public partial class Form1 : Form
   {
      public bool pause = false;
      public Thread mainThread;
      ...
      //start nowego wątku 
      private void btnStart_Click(object sender, EventArgs e)
      {
         mainThread = new Thread(new ThreadStart(mainLoopTh));
         mainThread.IsBackground = true;
         mainThread.Start();
      }
      //kod wykonywany w powyzszym wątku
     private void mainLoopTh()
     {
         while ("...lista warunków..." && (!pause)) 
         {
            ...
            eventList[index].execute();                 //wykonanie zdarzenia
            listBox.Add(eventList[index].Text);      //dodanie zdarzenia do listBox
         }
      }
      
      //naciśnięcie btnPause zatrzymyje lub wznawia mainThread
      private void btnPause_Click(object sender, EventArgs e)
      {
         if (mainThread.IsAlive)                        //sprawdza czy mainThread uruchominy
          {
             if(simulationClock > 0)
             {
                pause = !pause;                     
                if(pause) mainThread.Suspend();
                else mainThread.Resume();
              }
           }  
        }
}

I jeszcze screen okienka aplikacji. pewnie przyda sie dla lepszego zrozumienia kodu :-)
user image

0

Musisz wywołać metodę Invoke dla danej kontrolki. Przykład:

    public delegate void AddListItem(String item);

    public partial class ParentForm : Form
    {
        private Thread thread;
        private Delegate addDelegate;
        public ParentForm()
        {
            InitializeComponent();
            thread = new Thread(new ThreadStart(Run));
            thread.IsBackground = true;
            addDelegate = new AddListItem(AddItemToListBox);
        }

        private void buttonTest_Click(object sender, EventArgs e)
        {
            thread.Start();
        }

        private void Run()
        {
            while (true)
            {
                Thread.Sleep(2000);
                listBox.Invoke(addDelegate, "Item");
            }
        }

        private void AddItemToListBox(String item)
        {
            listBox.Items.Add(item);
        }
    }

[1] http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

0

Dlatego mówiłem, żeby użyć BackgroundWorkera - wtedy odpada połowa problemów z synchronizacją wątków. No, ale byłoby zbyt łatwo ;P

0

dzieki mykhaylo za podpowiedz
somekind masz racje - BackGroundWorker bedzie latwiejszym rozwiazaniem :] wybrałem wielowątkowość, bo przyda mi się wiedza ktorą nabędę, natykając się na różne zawiłości

dzienks za wszystkie sugestie.

0
mykhaylo napisał(a)

Musisz wywołać metodę Invoke dla danej kontrolki.

Jak w takim razie wyczyścić listę?

1 użytkowników online, w tym zalogowanych: 0, gości: 1