Wątek mi nie działa

0

Witam.

Piszę temat, gdyż nie mogę Sobie poradzić z wątkiem.
Jego kod wygląda tak:

unit Unit9;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Tlhelp32, StdCtrls, PsAPI, Vcl.Samples.Spin, Vcl.ExtCtrls, Math,
  Vcl.Menus, MMSystem;

type
  TAlarm = class(TThread)
  private

  protected
    procedure Execute; override;
  end;

 var
  Alarm:TAlarm;


implementation
uses Unit1;



procedure TAlarm.Execute;
begin
  FreeOnTerminate := true;
  while not self.terminated do
begin
if (Form1.Label7.Caption >= '100') then
begin
SNDPlaySound('Danger.wav', SND_FILENAME OR SND_ASYNC);
end;
end;
end;



Initialization
Alarm := TAlarm.Create(True);

end.

Chcę, by wątek sprawdzał mi label7 i jeżeli liczba w nim zapisana jest większa od 100 to żeby wył tak zwany alarm.

Checkbox wygląda tak:

procedure TForm1.CheckBox7Click(Sender: TObject);
begin
  if Checkbox7.Checked then
  begin
    Alarm.Resume;
  end
  Else
  begin
    Alarm.Suspend;
  end;
end;

Nie chcę tego robić w timerze, co by było łatwiejsze.
Proszę o pomoc.
Dziękuję

1

-1. CO TO ZNACZY NIE DZIAŁA?
0. formatuj kod

  1. użyj debuggera
  2. jeśli ma sprawdzać czy to co jest w label jest większe od 100 to musisz to zamienić na liczbę i z liczbą porównywać bo napis 2 jest większy od napisu 100
  3. dodaj po każdym sprawdzeniu sleep(100) - teraz sprawdzasz cały czas w kółko i o ile UI się nie wiesza to zużycie procesora na jednym rdzeniu masz 100%
  4. SND_ASYNC + wątek + brak sleep sprawi, że dźwięk będzie uruchamiany cały czas od nowa bez czekania aż poprzedni się skończy
  5. o ile tu nie jest to jakiś błąd (szczęście początkującego) to odwoływanie się z wątku do elementów UI jest niepoprawne
  6. masz ogromne braki w podstawach a bierzesz się za jedną z najtrudniejszych rzeczy - programowanie wielowątkowe. Chyba chcesz za dużo przeskoczyć
0

W sumie to jeśli dźwięk z pliku Danger.wav jest długi np. na kilka sekund to obecny kod może zostać - wystarczy usunąć flagę SND_ASYNC. W ten sposób program będzie oczekiwał na zakończenie odgrywania dźwięku, a że całość działa w wątku pobocznym, to interfejsu nie zamrozi, a i zużycie procka spadnie.

Co do reszty - poprzednik podał wystarczająco dużo niedociągnięć.

0
(Form1.Label7.Caption >= '100')

Przecież do komponentu Label nie wprowadzasz.
Utwórz dodatkową zmienną, aby z niej korzystał wątek (może być w klasie, lub globalna), gdyż korzystanie z kontrolek jest wolne, a i bez synchronize() (co było wspomniane) powoduje błędy.
Poza tym, tak jak napisali w poprzednich - porównywać trzeba liczby, a nie łańcuchu tekstowe.
Zmienna pomocnicza powinna być typu liczbowego i być aktualizowana wraz z Label7 (konwersja typów).

I ogólnie nie widzę potrzeby kilku wątków.
W końcu wraz z modyfikacją Label7 (robisz to z kodu) możesz uruchomić dźwięk (z SND_ASYNC z głównego wątku) i ewentualnie go zatrzymać za pomocą SND_PURGE.

0

Korzystanie z kontrolek jest wolne? No bez przesady. Fakt, szybciej odczytać zwykłą zmienną niż właściwość kontrolki, ale to w takim przypadku nie jest w ogóle zauważalne.

Poza tym jeśli chodzi o Synchronize, to jest potrzebne przy ZAPISIE. Przy odczycie nie ma żadnego sensu. Jednak nie jest ładnie tak mieszać logikę z GUI i powinieneś tutaj zadbać o to, żeby nie odczytywać bezpośrednio danych z kontrolki, tylko w jakiś inny sposób. Ale staraj się nie używać zmiennych globalnych, bo to też nie jest dobre. Pole do popisu masz spore. Ja w pierwszym strzale zrobiłbym callbacka, który by mi zwracał odpowiednią wartość.

0

@Juhas:
Fakt, szybciej odczytać zwykłą zmienną niż właściwość kontrolki [...]

Wszystko zależy od tego jak to wygląda pod spodem - czy właściwość daje bezpośredni dostęp do pola, czy jednak posiada akcesor z jakąś logiką. Być może dostęp bezpośredni do pola może być na niskim poziomie redukowany do operacji atomowej, ale tego nie jestem pewien.

Poza tym jeśli chodzi o Synchronize, to nie jest potrzebne przy ZAPISIE.

Obstawiam, że przez przypadek napisałeś to "nie". Jeśli zapis jest atomowy (np. modyfikacja inta) to nic nie trzeba synchronizować. Jednak jeśli modyfikuje się dane o większej wadze to jest konieczna - tym bardziej, jeśli co najmniej dwa wątki mają możliwość ingerencji w te dane.

Przy odczycie nie ma żadnego sensu.

Owszem - ma sens. Wyobraź sobie co się stanie, jeśli jeden wątek będzie modyfikował bufor danych o wadze kilku megabajtów, a drugi wątek w tym czasie będzie z tego bufora odczytywał. O ile nie skończy się to wyjątkiem, to wątek czytający z bufora może odczytać dane częściowo zmodyfikowane.

0

Jakoś to "nie" wkradło mi się przypadkiem, nie wiem skąd. Natomiast tutaj piszemy o pobieraniu danych z okienka GUI. W przypadku pytacza, to nie są RichEdity z milionami znaków, tylko proste labele, więc tutaj odczyt z Synchronize nie ma sensu. Natomiast zgodzę się z tym, co mówisz, czyli przy dużych paczkach danych ma to sens. Chociaż tutaj też się rodzi pytanie, jak to działa pod spodem. Czy update takiej paczki jest operacją atomową, czy nie. No, jeśli zmieniamy zawartość w pętli, no to sprawa jest jasna. Ale jeśli robimy to jedną operacją, to już niekoniecznie jednak :)

0

Dziwne, mi działa.

0
Juhas:

W przypadku pytacza, to nie są RichEdity z milionami znaków, tylko proste labele, więc tutaj odczyt z Synchronize nie ma sensu.

Owszem, jednak Ty napisałeś o synchronizacji ogólnie, bez rozróżnienia przypadków, co może wprowadzać w błąd - stąd mój komentarz.

Natomiast zgodzę się z tym, co mówisz, czyli przy dużych paczkach danych ma to sens.

Tu nie chodzi o rozmiar danych, a o skalę modyfikacji. Im dłużej trwa owa modyfikacja i ma większą złożoność, tym większe prawdopodobieństwo, że inny wątek wtrąci się w nieodpowiednim momencie i albo spowoduje tym powstanie wyjątku, albo odczyta na wpół zmodyfikowane dane. W obu przypadkach jest to katastrofa.

Ale jeśli robimy to jedną operacją, to już niekoniecznie jednak :)

Jeśli owa operacja jest atomowa to nie trzeba, bez względu na to czy dotyczy odczytu czy modyfikacji :]

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