CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Modyfikacja podczas działania Sleep'a
Strona 1 z 2

Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 02:01
przez nvdante
Witam

Napisałem sobie maleńki programik, który ogólnie mówiąc działa, ale chciałbym go troszkę usprawnić.
Otóż program po naciśnięciu Start wykonuje pętlę, którą można przerwać przyciskiem Stop.
Pętla polega na wykonaniu polecenia, które jest opóźniane Sleep'em na konkretny czas podawany przez TrackBar1, np.: TrackBar1->Position = 1000, więc Sleep(1000) ... następnie polecenie.
Pod przycisk Stop wrzuciłem fragmentu kodu Barona odnośnie przerywania działania Application->ProcessMessages(); if(przerwij == true) break;
Problem jednak polega na tym, że polecenie Sleep ( lub pętla, nie mam 100% pewności ) zatrzymuje ingerencję w Form1 na czas jednego obrotu, a co za tym idzie każda ingerencja w przycisk, TrackBar1, czy nawet próba zamknięcia programu powoduje najpierw zakończenie przetwarzania ( pomimo instrukcji przerwania ). Nie ma kłopotu, gdy Sleep jest 100, ale przy 100000 zaczyna to być uporczywe :/
Ma ktoś może jakiś pomysł?
Oczywiście Sleep mogę ominąć, jeśli tylko ktoś podpowie jak inaczej zatrzymać wykonanie polecenia o wartość TrackBar1.
Próbowałem "obejść" problem i podzieliłem wartość TrackBar1 na 10, żeby utworzyć 10 Sleepów, ale to także nie pozwala na edycję Form1 podczas przeskakiwania między Sleep'ami.

Z góry dziękuję za podpowiedzi.

Pozdrawiam

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 09:50
przez Cyfrowy Baron
Funkcja Sleep wstrzymuje całą aplikację, a nie tylko pętlę. W pliku pomocy można przeczytać:

Plik pomocy Embarcadero RAD Studio 2010 napisał(a):Delay program execution for a specified number of milliseconds.

Sleep pauses program executions as specified by the milliseconds parameter. Under Windows, Sleep is just a link to the Sleep function in the API system.




nvdante napisał(a): jak inaczej zatrzymać wykonanie polecenia o wartość TrackBar1.


Jakiego polecenia? Opisz w sposób zrozumiały, co konkretnie próbujesz osiągnąć.



nvdante napisał(a):nawet próba zamknięcia programu powoduje najpierw zakończenie przetwarzania ( pomimo instrukcji przerwania ).


Nie rozumiem! Jakiego przetwarzania?

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 11:22
przez nvdante
Jeśli chodzi o polecenie to używam najpierw odczytania pozycji TrackBar1, a później chodzi o odpalenie MediaPlayer1, więc jak widzisz nic skomplikowanego. Dodam tylko, że nie chodzi tu o zmianę głośności, bo dane z TrackBar1 są interpretowane jako czas.
Pisząc "zakończenie przetwarzania" miałem na myśli konieczność zakończenia poleceń w pętli, która już się zaczęła.
Skoro Sleep zatrzymuje cały program to jak można inaczej nakazać programowi wykonanie danego polecenia z dokładnym opóźnieniem, ale korzystając z innej metody?
Dla przykładu przyjmijmy, że chcę wyświetlić w Label1 jakiś napis, ale chcę, aby stało się to po na przykład 10s po kliknięciu Start, a w tym czasie chcę nadal mieć możliwość przerwania tego oczekiwania.

Pozdrawiam

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 11:47
przez polymorphism
Funkcję Sleep możesz zamienić takim kodem:
KOD cpp:     UKRYJ  
clock_t wait_ms = ...; // czas wstrzymania
clock_t time_ms = clock();

while(!przerwij && clock() - time_ms < wait_ms)
{
        Application->ProcessMessages();
//      Sleep(1);  <--- odkomentuj to, jeśli pętla będzie zużywać za dużo mocy CPU
}
 

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 11:57
przez nvdante
Dokładnie o to mi chodzi. Podczas działania programu można na bieżąco zmieniać wszystko.
Jest jednak maleńki problem. Gdy klikam Stop to program zaczyna wariować i ostatecznie się zawiesza.
W sumie nie widzę powodu, kod jest taki:
KOD cpp:     UKRYJ  
bool przerwij = false;
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
przerwij = false;

for (int i=0; i<100000000; i++)
        {
        int x = TrackBar1->Position * 16.6666;
        clock_t wait_ms = x;
        clock_t time_ms = clock();

        while(!przerwij && clock() - time_ms < wait_ms)
        {
                Application->ProcessMessages();
        }
        MediaPlayer1->Open();
        MediaPlayer1->Play();
        }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton2Click(TObject *Sender)
{
przerwij = true;
}

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 12:08
przez Cyfrowy Baron
Użyj obiektu Timer i tam odmierzaj czas.
W tym fragmencie kodu, który przedstawiłeś zmienna przerwij tylko wyłącza zegar, nie zatrzymuje pętli for. Pętla działa do końca.

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 12:41
przez nvdante
Czy w takim razie powinienem przepisać całą pętlę do środka do:
KOD cpp:     UKRYJ  
while(!przerwij && clock() - time_ms < wait_ms)
        {
                Application->ProcessMessages();
        }


??

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 13:15
przez Cyfrowy Baron
Ja wciąż nie rozumiem co Ty próbujesz osiągnąć, ale jedno jest pewne jeżeli chcesz przerwać jedną z pętli w zależności od stanu zmiennej to powinieneś ją umieścić wewnątrz tej pętli z warunkiem, a to wewnątrz której to zależy od tego, którą pętle chcesz przerwać.

Przerwanie obydwu pętli:
KOD cpp:     UKRYJ  
bool przerwij = false;
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
przerwij = false;

for (int i=0; i<100000000; i++)
        {
        int x = TrackBar1->Position * 16.6666;
        clock_t wait_ms = x;
        clock_t time_ms = clock();

        while(clock() - time_ms < wait_ms)
        {
                Application->ProcessMessages();
                if( przerwij == true ) return;
        }
        MediaPlayer1->Open();
        MediaPlayer1->Play();
        }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton2Click(TObject *Sender)
{
przerwij = true;
}

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 13:25
przez nvdante
Działa znakomicie, dokładnie o to mi chodziło.
Dalsza część kodu to już tylko działania matematyczne, z którymi sobie powinienem poradzić.
Jak zawsze dziękuję za pomoc Wam obu.

Pozdrawiam

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 14:22
przez nvdante
Jeszcze jedno pytanko.
Taki kod:
KOD cpp:     UKRYJ  
x = (60/TrackBar1->Position)*1000;

nie zawsze zwraca wartość bez liczb po przecinku. Nie chcę wyświetlać tej wartości tylko użyć ją dalej w programie, ale w taki sposób, żeby dane polecenie uruchomiło się po np.: 1583ms, a nie po 2000ms. Jak wymusić na programie dokładne wykonanie polecenia w zadanym czasie?

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 14:33
przez polymorphism
A ten trackbar w jakich jednostkach jest?

Tak czy siak, spróbuj w ten sposób wykonać obliczenia:
KOD cpp:     UKRYJ  
x = 60 * 1000 / TrackBar1->Position;

Od strony matematycznej różnica żadna, ale od programistycznej już jest.

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 14:50
przez nvdante
Już miałem napisać, że jest źle, ale najwidoczniej sam coś zepsułem przy przepisywaniu ;)
Jest super, właśnie o to chodziło.
Jeszcze raz dzięki za pomoc.

Pozdrawiam

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 19:23
przez nvdante
Zastanawia mnie jeszcze jeden fakt.
Logicznie sprawdzając wyrażenie typu:
KOD cpp:     UKRYJ  
60 * 1000 / TrackBar1->Position


dla TrackBar1 = 60 powinno dać wartość 1000.
Skoro tak to dlaczego możliwe jest, aby gołym okiem, zapętlając wykonywanie polecenia co 1000ms zaobserwować przesunięcie, a dokładniej program wykonuje się z takimi wartościami sekundowymi:
0, 1, 2, 3, 4.1, 5.1, 6.1, 7.2, 8.2 ... itd
Z tego co widać program nie wykonuje się o dokładnej chwili tylko zmiennej.
Jakiś pomysł dlaczego i jak to poprawić?
Niby ułamki sekund są mało ważne, ale w przypadku takiego programu bardzo mi na tym zależy.

Pozdrawiam

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 20:37
przez Cyfrowy Baron
Ale o co Tobie chodzi? O to, że zegar nie odlicza precyzyjnie sekund czy, że wizualizacja tych sekund nie wypada co zadany czas?!

Re: Modyfikacja podczas działania Sleep'a

Nowy postNapisane: niedziela, 29 stycznia 2012, 22:54
przez polymorphism
(...) dlaczego możliwe jest, aby gołym okiem, zapętlając wykonywanie polecenia co 1000ms zaobserwować przesunięcie (...) ?

Ano dlatego, że ani Twój "sleep", ani pozostały kod nie wykonują się za każdym razem w takim samym czasie. System windows nie jest RTOS-em, więc nie oczekuj, że wszystko wykonuje się dokładnie co do mikrosekundy. Nawet zakładając, że pętla opóźniająca czeka dokładnie sekundę, to zważ, że jest jeszcze czas, który jest potrzebny do wykonania pozostałej części kodu zawartego w pętli.