Odwołanie się do indeksu tablicy dynamiczej z wewątrz uruchomionego wątku

0

Witam,
Nidy nie zdawałem pytań na tym forum bo zawsze znajdowałem odpowiedź w postach innych użytkowników, ale nie tym razem. Mam tablice dynamiczną w której trzymam wątki, i podczas wykonywaniu wątku potrzebuję zwrócić jakąś informację w której muszę użyć indeksu tablicy wykonywanego wątku. Jest jakiś sposób żeby uzyskać taką informację, dla którego indeksu tablicy wątek coś wykonał? Oczywiście zrobiłem to w ten sposób że przekazuje indeks tablicy do wątku pod czas jego tworzenia, ale nie jest to chyba eleganckie, jest jakiś inny sposób?

0

Ja wolę stworzyć klasę która pochodzi od TThread, wyniki zostają w klasie.

0

Zastosowałem to rozwiązanie ale mam problem podczas zwalniania klasy. Gdy użyje Free albo Destroy zawiesza mi się cały program a debuger nic nie wyrzuca i nie wiem dlaczego. Przed wywołaniem Free lub Destroy zatrzymywałem działanie wątku i nic, też z własnym zadeklarowanym destructorem czy bez niego też to samo. Dodam że inna klasa w tym samym programie działa tak samo i zwalnianie jej zawiesza program. A robię to tak:

...

type
  TObsluga = class(TThread)
  private
    Indeks: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create(ID: Integer);
    destructor Destroy; override;
  end;

...

constructor TObsluga.Create(ID: Integer);
begin
  inherited Create(False);
  Self.Indeks := ID;
//jescze jakies inne zmienie ustawiam
end;

destructor TObsluga.Destroy;
begin
//tu jakis komunikat wywoluje
  inherited;
end;

procedure TObsluga.Execute;
begin
  while not((Application.Terminated) or (Terminated)) do
  begin
    // coś tam się robi
  end;
end;

...

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  if Assigned(GlownyWatek) then
  begin
    GlownyWatek.Free;
  end;
end;

...

end.

Dodam, że jeśli użyje Terminate zamiast Free a w Execute wstawię przed pętlą while FreeOnTerminate na true to też się program zawiesza

0

Jeśli ustawisz FreeOnTerminate to wątek zwolni się sam po zakończeniu działania. Użycie Terminate powoduje zmianę Terminated na true i twoim zadaniem w metodzie Execute jest jak najszybsze sprawdzenie tego warunku i wyjście z tej metody. Jeśli tego nie zrobisz wątek nie zostanie zwolniony.

0

Ale to przecież napisałem pod kodem, że też robiłem w ten sposób, użyłem FreeOnTerminate na True przed while i kończyłem Buttonem za pomocą Terminate a program po tym się i tak zawiesza. Bo jeśli używam Terminate to pętla się przecież kończy

while not((Application.Terminated) or (Terminated)) do

, dodatkowo w while mam jeszcze jedną pętle ale tam też mam warunek Terminated=True wtedy robię break a i tak się wiesza.

0
while not((Application.Terminated) or (Terminated)) do
while (not Application.Terminated) and (not Terminated) do

Mam dziwne wrażenie że to tak powinno być.

0

Ten kod nie ma sensu:

  if Assigned(GlownyWatek) then
  begin
    GlownyWatek.Free;
  end;

Ponieważ nawet jeśli zwolnisz GlownyWatek to Wskaźnik i tak nie zostanie zamieniony sam na nil.

Mając np. taki wątek:

procedure TTestThread.Execute;
begin
  FreeOnTerminate := false;
  while not(Terminated) do
  begin
    Beep;
    Sleep(7000);
    // coś tam się robi
  end;
  Sleep(100);
  Beep;
  Sleep(100);
  Beep;
end;

Gdy w głównej aplikacji zaczniesz zwalniać go np. tak:

procedure TForm1.Button2Click(Sender: TObject);
begin
  Thread.Free;
  Application.Terminate;
end;

To główna forma będzie zacięta do momentu gdy nie wyjdziesz z Execute i dopiero wtedy wątek zostanie poprawnie zwolniony.

Jest możliwość też wymuszenia zamknięcia wątku np. tak:

TerminateThread(Thread.ThreadId, 404);

ale wtedy nie mamy możliwości dowiedzenia się czy wątek zrobił to co powinien jest po prostu ubity.

0

Ok, dobra doszedłem w czym jest problem wewnątrz wątku mam funkcje która blokuje pętle, jest to accept z Winsock i dopóki nie przyjdzie jakieś połączenie cały wątek wisi. Teraz pytanie czy jest jakaś możliwość wrzucenia accepta w jakiegoś trya czasowego np po 1 sekundzie idzie dalej i zwraca. To

TerminateThread(Thread.ThreadId, 404);

sądzę że zadziała ale będzie to ostateczność po którą wolałbym nie sięgać

0

Nie wiem na jakim poziomie obsługujesz winsock i czy to są blokujące gniazda czy nie, ale w źródłach TClientSocket czy TServerSocket jest coś takiego jak WaitForData czy TimeOut - zobacz jak to jest tam zakodowane. Nawet jeśli chcesz duży TimeOut np. 30 sekund to zrób sobie zamiast tego 30 razy 1 sekunde TimeOut a po 1 sekundzie sprawdzaj czy coś nie chce zamknąć wątku, wyjdzie na jedno a użytkownik nie będzie musiał czekać zbyt długo na reakcję programu.

0
...
 
type
  TObsluga = class(TThread)
  private
    Done:Boolean;

...

procedure TObsluga.Execute;
begin
  ...
  Done:=true;
end;
 
...
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(GlownyWatek) then
  begin
    GlownyWatek.Terminate;
    while not GlownyWatek.Done do begin end;
  end;
end;
 
...
 
end.
0

To nic nie wnosi do rozwiązania problemu bo i tak watek będzie wisiał na funkcji accept. Podejrzałem TIdCustomTCPServer z Indy które korzysta z Winsock i funkcji accept i to nie różni się znacząco od mojego kodu, tylko później używane jest FreeAndNil ale też nie bezpośrednio do klasy gdzie jest użyte accept więc to też nic nie wyjaśnia a przeszukanie wszystkich modułów od indy to kilka dni jak nic. Wymyśliłem że po wysłaniu Terminate od razu wykonam connect i funkcja się odwiesi i zwolni się wtedy cały wątek.

usunięcie cytowania całego poprzedniego posta - fp

0
jagro napisał(a):

... To nic nie wnosi do rozwiązania problemu ...
No bo problem zupełnie inny niż przedstawiłeś.
Mówiłeś że masz problem z zakończeniem wątku no to dostałeś jak go zakończyć.
Jak masz problem z obsługą serwera to pokaż kod i powiedz jaki masz z tym problem.
Zawsze możesz ustawić TimeOut na powiedzmy 200 ms, więc po 200ms wykona się kolejny krok pętli, wtedy program sprawdzi ten warunek pętli Terminated

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