Wątki - jak utworzyć aby były widoczne w "Menedżerze Windows"

0

mam pytanie jak w temacie:
poniższy fragment kodu wprawdzie tworzy 3 wątki ale nie pokazuje ich w Procesach odrębnie

begin
{ utworzenie trzech wątków }
  TGoThread.Create(1);
  TGoThread.Create(2);
  TGoThread.Create(3);
end;

Co powinno być w kodzie aby były widoczne 3 wątki.

dodanie znacznika <code class="delphi"> - furious programming

1

O co chodzi? Wątki to nie oddzielne procesy wiec jak mają być widoczne w procesach? Jeżeli utworzysz wątki to co najwyżej zobaczysz że zmieniła się ilość wątków w kolumnie wątki Menedżera zadań Windows.

1

Proces to nie to samo co wątek. W ten sposób wątki zostaną poprawnie stworzone, ale stracisz nad niemi kontrolę z zewnątrz. Wątki możesz podejrzeć przez View -> DebugWindows -> Threads dla Delphi7.

0

Tak, sorki. To ja źle przedstawiłem sprawę, chodzi o widoczność w wątkach systemu.

0

Masz na myśli w procesach systemu?

0

Tak to miałem na myśli na początku.

0

http://www.catch22.net/tuts/undocumented-createprocess
Aczkolwiek odradzam użycie nieudokumentowanych właściwości.

1

oprócz stworzenia trzeba jeszcze zadbać o to, żeby się uruchomiły i coś robiły bo jak się nie uruchomią to no nie są uruchomione, a jak nie mają co robić to się zaraz kończą i też ich nie ma

0

W moim programie mają na zmianę czasowo sprawdzać zawartość katalogów

0

a sprawdzają? a są uruchamiane? Konstruktor nie jest z klasy bazowej więc z jakimi parametrami jest wywoływany konstruktor klasy TThread?

0

Na chwilę obecną bazuje na przykładzie z rozdziału 8 Kompendium, w którym konstruktor wygląda następująco :

TGoThread = class(TThread)
  private
    FV : Integer; // wylosowana liczba
    FCounter : Integer; // numer wątku
    procedure SetProprties;
  protected
    procedure Execute; override;
  public
    constructor Create(Counter : Integer);
  end;

dodanie znacznika <code class="delphi"> - furious programming

0

szopenfx konstruktor wygląda tak:

constructor TGoThread.Create(Counter: Integer);
begin
  inherited Create(False);
  FCounter := Counter;
end;
0

Tak utworzony wątek startuje od razu więc wykonuje kod w procedurze Execute po jego wykonaniu wątek kończy swoje działanie. Co masz w Execute? Być może tam jest tylko jakaś krótka operacja którą wątek wykonuje momentalnie i kończy swoje działanie tak szybko że nawet nie jesteś w stanie tego zauważyć.

0

jest tylko

 Synchronize(SetProprties); 

SetProprties to procedura która zawiera :

procedure TGoThread.SetProprties;
var
  i : Integer;
begin
  FreeOnTerminate := True; // zwolnij po zakończeniu wątku
  Randomize;
  FV := Random(1000);
  { odnalezenie komponentu na formularzu }
  TProgressBar(MainForm.FindComponent('ProgressBar' + InttoStr(FCounter))).Max := FV;
  for i := 0 to FV do
  begin
    Sleep(10);
    TProgressBar(MainForm.FindComponent('ProgressBar' + IntToStr(FCounter))).Position := i;
  end;
end; 
0

Taki kod będzie wykonywał się w zależności od wylosowanej liczby od ~0 ms do ~9990 ms wiec maksymalnie niecałe 10 sekund. O tym że kod jest źle napisany nie muszę wspominać ale to temat na inną bajkę...

1

użycie wątku z takim kodem to nieporozumienie

0

Słyszałeś kiedyś o zdarzeniach? W wątku też możesz je wywoływać zrób sobie jakieś OnProgress i w nim aktualizuj ProgressBar (to zdarzenie wywołuj w Synchronize)

0

po pierwsze WSZYSTKO to co jest wołane przez synchronize wykonuje się w ramach wątku GŁÓWNEGO więc w tym konkretnie przypadku wątek jako taki całkowicie traci sens

0

Nie jestem mistrzem w wątkach. I nie pamiętam kiedy ostatnio pod VCL robiłem coś na wątkach. Ponieważ ostatnio jakl coś robię większego, to raczej pod WinAPI. I nie wiem czy o to chodzi. Ale kiedy użyłem poniższego kodu pod Delphi 7 na czystym projekcie. I odpaliłem sobie Process Explorer i ubiłem drugi wątek mojego porcesu z listy to Caption Formatki przestał się zmieniać. Czyli chyba to jest to o co Tobie chodzi. Żeby wątki były widoczne. O ile one nie są zawsze widoczne tam gdzie trzeba. A z managera zadań korzystam tak rzadko (napisałem sobie swój własny "ubijacz porcesów", pod WinAPI ofcoz), że nie wiem gdzie tam spojrzeć aby zobaczyć konkretne informacje o wątkach pod Windows 7 64 bit i je ubijać.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Math;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender : TObject);
  private
  public
  end;

  TSthThread = class(TThread)
  protected
    procedure Test;
    procedure Execute; override;
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

procedure TSthThread.Test;
begin
  Form1.Caption := Format('%.8d', [RandomRange(10000000, 100000000)]);
end;

procedure TSthThread.Execute;
begin
  while True do
  begin
    Synchronize(Test);
    Sleep(80);
  end;
end;

procedure TForm1.FormCreate(Sender : TObject);
var
  Thr : TSthThread;
begin
  Randomize;
  Thr := TSthThread.Create(False);
  Thr.FreeOnTerminate := True;
end;

end.
4

Łap przykład mniej więcej jakoś tak powinno to wyglądać:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TOnProgress = procedure(Sender: TObject; Progress, MaxProgress: Integer) of object;

  TMyThread = class(TThread)
  private
    fProgress, fProgressMax: Integer;
    fCounter: Integer;
    fOnProgress: TOnProgress;

    procedure DoOnProgrss;
  protected
    procedure Execute; override;
  public
    property Counter: Integer read fCounter write fCounter;
    property OnProgress: TOnProgress read fOnProgress write fOnProgress;
    constructor Create(Counter: Integer; OnProgress: TOnProgress = nil);
  end;

  TForm1 = class(TForm)
    btnStart: TButton;
    ProgressBar1: TProgressBar;
    ProgressBar2: TProgressBar;
    ProgressBar3: TProgressBar;
    procedure FormCreate(Sender: TObject);
    procedure btnStartClick(Sender: TObject);
  private
    { Private declarations }
    procedure OnProgress(Sender: TObject; Progress, MaxProgress: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TMyThread.DoOnProgrss;
begin
  fOnProgress(Self, fProgress, fProgressMax);
end;

procedure TMyThread.Execute;
var
  i: Integer;
begin
  fProgressMax:= Random(1000) + 1;
  for i:= 0 to fProgressMax do
  begin
    Sleep(10);
    fProgress:= i;
    if Assigned(fOnProgress) then
      Synchronize(DoOnProgrss);
  end;
end;


constructor TMyThread.Create(Counter: Integer; OnProgress: TOnProgress = nil);
begin
  inherited Create(False);
  fCounter:= Counter;
  fOnProgress:= OnProgress;
  FreeOnTerminate:= True;
end;


procedure TForm1.OnProgress(Sender: TObject; Progress, MaxProgress: Integer);
begin
  case TMyThread(Sender).Counter of
    1: begin
         ProgressBar1.Max:= MaxProgress;
         ProgressBar1.Position:= Progress;
       end;
    2: begin
         ProgressBar2.Max:= MaxProgress;
         ProgressBar2.Position:= Progress;
       end;
    3: begin
         ProgressBar3.Max:= MaxProgress;
         ProgressBar3.Position:= Progress;
       end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
end;

procedure TForm1.btnStartClick(Sender: TObject);
begin
  TMyThread.Create(1, OnProgress);
  TMyThread.Create(2, OnProgress);
  TMyThread.Create(3, OnProgress);
end;

end.
0

Dzisiaj będę dopisywał część do obsługi plików i katalogów - wyszukiwanie liczby plików w wybranych katalogach. Czy muszę szczególną uwagę zwrócić na jakieś polecenia, funkcje itp ? Z góry dziękuje za wskazówki.

0

no właśnie użyłem faAnyFile jak niżej :

liczplk1:=0;
  znajdz := FindFirst(edtWatek1.Text + '\*.*', faAnyFile, SR); // odnajdz
  while (znajdz = 0) do // dopoki liczba znalezionych plikow nie bedzie rowna 0
  begin
    znajdz := FindNext(SR); // szukaj dalej
    showmessage('katalog' + SR.Name); // kontrola co aktualnie sprawdzamy
    if (SR.Name='.') or (SR.Name='..')
    then
    begin
      showmessage('katalog' + SR.Name); // kontrola co aktualnie sprawdzamy
      memWatki.Lines.Add(SR.Name);
      continue
    end
    else Inc(liczplk1);
    memWatki.Lines.Add(edtWatek1.Text + SR.Name);
end;
  memWatki.Lines.Add(IntToStr(liczplk1))

Wg takiego sposobu zlicza mi wszystko łącznie z podfolderami, ale nie mogę wyłuskać liczby plików

0

No to albo się babrzesz w VCL albo korzystasz z mojej rady i używasz funkcji z modułu Windows. Wszystko opisano na MSDNie. Ale nic nie narzucam. Wyszukiwanie należy zrobić rekurencyjnie, bo tak wychodzi najlepiej. Także niestety albo googlujesz sam i kombinujesz, bo na przykład pod WinAPI mozesz liczyć ode mnie dopiero jutro. Chyba, że znajdziesz sobie wśród dołączanych przeze mnie plików na tym forum moduł useful_winapi.pas i tam być może w wersji jaką wrzucałem był już kod na wyszukiwanie plików. Ale tego teraz nie sprawdzę.

0
olesio napisał(a)

Wyszukiwanie należy zrobić rekurencyjnie, bo tak wychodzi najlepiej.

Uściślając - jeśli chcesz wyszukiwać pliki jedynie w jednym katalogu (bez podfolderów), to wystarczy metoda iteracyjna - w pętli szukasz pliki i po znalezieniu robisz z nimi to, co chcesz zrobić; Natomiast jeśli trzeba przeszukać także podfoldery - jedynym logicznym rozwiązaniem jest metoda rekurencyjna, w której po znalezieniu katalogu wywołujesz procedurę rekurencyjnie, dodając do parametru z aktualną ścieżką nazwę znalezionego katalogu oraz separator \.

1

Ok, zgodnie z obietnicą odpisuję teraz z PC. Szkoda, że @roboskobo spocząłeś na laurach i nie chciało się Tobie poszukać w google pliku, o którym pisałem. Pierwszy wynik z Google to wątek na forum unit1. Jest to dokładnie miejsce, gdzie jest właściwy załącznik. Nic tylko się zarejestrować za darmo i pobrać go. Wtedy dawno już miałbyś temat ogarnięty.

Poniższy kod tworzony był pod Delphi 7 i do celów użycia w czystym WinAPI. Także, jeśli chcesz wersji z wsparciem dla UNICODE - przerób sobie kod. Jeśli chcesz się czepiać, jak niektórzy tutaj kiedyś, że niepotrzebnie co chwilę mam sprawdzanie czy coś <> nil, zamiast zrobić to poprzez zmienną typu boolean - przerób sobie kod. Jeśli chcesz na listingu mieć też same podkatalogi - przerób sobie kod. Nie podobają się Tobie nazwy zdarzeń i sposób działania - wtedy ponownie, samodzielnie przerób sobie kod. Dostosuj go do własnych potrzeb. Ja się na to nie pogniewam :) To tylko prosty przykład.

type
  TFileSearchOnFindProc = procedure(FoundFileName : string);
  TFileSearchProgressProc = procedure(CurrentSearchPath : string);

function AddBackSlash(Path : string) : string;
begin
  Result := '';
  if Path <> '' then
  begin
    if Path[Length(Path)] <> '\' then
    begin
      Result := Path + '\';
    end
    else
    begin
      Result := Path;
    end;
  end;
end;

procedure FileSearch(const PathName, FileName : string; const InDir : boolean;
  FileSearchOnFindProc : TFileSearchOnFindProc;
  FileSearchProgressProc : TFileSearchProgressProc);
var
  H : THandle;
  Path : string;
  WFD : TWIN32FindData;
begin
  Path := AddBackSlash(PathName);
  if @FileSearchProgressProc <> nil then
  begin
    FileSearchProgressProc(Path);
  end;
  H := Windows.FindFirstFile(PChar(Path + FileName), WFD);
  if H <> INVALID_HANDLE_VALUE then
  begin
    try
      repeat
        if (WFD.dwFileAttributes and FILE_ATTRIBUTE_ARCHIVE =
          FILE_ATTRIBUTE_ARCHIVE) or (WFD.dwFileAttributes and
          FILE_ATTRIBUTE_NORMAL = FILE_ATTRIBUTE_NORMAL) then
        begin
          if @FileSearchOnFindProc <> nil then
          begin
            FileSearchOnFindProc(Path + WFD.cFileName);
          end;
        end;
      until not FindNextFile(H, WFD);
    finally
      Windows.FindClose(H);
    end;
  end;
  if InDir then
  begin
    H := Windows.FindFirstFile(PChar(Path + '*.*'), WFD);
    if H <> INVALID_HANDLE_VALUE then
    begin
      try
        repeat
          if (WFD.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY =
            FILE_ATTRIBUTE_DIRECTORY) and (Copy(WFD.cFileName, 1, 1) <> '.') and
            (WFD.cFileName <> '..') then
          begin
            FileSearch(Path + WFD.cFileName, FileName, True,
              FileSearchOnFindProc, FileSearchProgressProc);
          end;
        until not FindNextFile(H, WFD);
      finally
        Windows.FindClose(H);
      end;
    end;
  end;
end;

procedure FileSearchOnFindProc(FoundFileName : string);
begin
  Form1.Memo1.Lines.Add(FoundFileName);
end;

procedure FileSearchProgressProc(CurrentSearchPath : string);
begin
  Form1.Caption := CurrentSearchPath;
end;

procedure TForm1.Button1Click(Sender : TObject);
begin
  Memo1.Clear;
  Memo1.Lines.BeginUpdate;
  FileSearch('D:\TEST', '*.*', True, FileSearchOnFindProc, FileSearchProgressProc);
  Memo1.Lines.EndUpdate;
end;
0

@olesio Dziękuje bardzo za kod - zaraz będę go analizował. Może na laurach nie spocząłem od razu lecz chwilowy brak czasu na dalsze zgłębianie wiedzy na temat wątków.
Generalnie wątki są dla mnie nowym tematem. Czytałem, że do pracy z wątkami na początku lepiej nie używać Synchronize, bo można namieszać w kodzie. Czytam od nowa o wątkach, tak aby dobrze zrozumieć ich działanie.

0

Czytałem, że do pracy z wątkami na początku lepiej nie używać Synchronize, bo można namieszać w kodzie.

Piszesz tak, jakby metoda Synchronize służyła jedynie do obfuskacji kodu, a przecież tak nie jest; Zapoznaj się z tematem wątków najlepiej od początku i na spokojnie, bo z tym tematem początkujący mają podobne problemy, jak ze wskaźnikami czy rekurencją - "it's magic".

0

Ja uczyłem się wątków z http://thaddy.co.uk/threads/Ch2.html Wyjaśnione jest tam wiele problemów, które mogą pojawić się przy pisaniu aplikacji wielowątkowych lub pułapek na które można się nadziać. Niestety linki do obrazków i kodów źródłowych są nieaktywne i nie wiem czy dalej można zrozumieć wszystko co jest zawarte w tekście bez nich.

*Edit: znalazłem mirror http:*www.seti.net/indepth/threads/threads.php

0

Nie czytałem wszystkiego ale przemknęło mi monitorowanie katalogów - czyli FindFirstChangeNotification:

http://edn.embarcadero.com/article/21743

ew. http://www.angusj.com/delphi/dirwatch.html

Lub komponentowo:
TJvChangeNotify - http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvChangeNotify
TShellChangeNotifier - http://delphi.about.com/od/kbwinshell/l/aa030403a.htm

A wątki z ich stosem pokazuje MS (Sysinternals) Process Explorer: http://technet.microsoft.com/pl-pl/sysinternals/bb896653

0

Robiłem jednak wątki w VCL, zacząłem w ten sposób i chciałem poznać na początek ten sposób posługiwania się wątkami.
Niestety nie do końca działa - mianowicie program jest jakby zawieszony (nie można go przesunąć czy zatrzymać)
Jeżeli ktoś ma ochotę przejrzeć kod to wrzucam go .

  TOnPostep = procedure(Sender: TObject; Postep, MaxPostep: Integer) of object;
//  TOnPostep = procedure(Sender: TObject; Postep: Integer) of object;

  TMyThread = class(TThread)
  private
    FCounter: Integer;  //numer watku
    licz: Integer;
    liczMax: Integer; //liczba
    fOnPostep: TOnPostep;
    procedure DoOnPostep;
  protected
    procedure Execute; override;
  public
    property Licznik: Integer read FCounter write FCounter;
    property OnPostep: TOnPostep read fOnPostep write fOnPostep;
    constructor Create(Counter: Integer; OnPostep: TOnPostep = nil);
  end;
...
  private
    procedure OnPostep(Sender: TObject; Postep, MaxPostep: Integer);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrm: TMainFrm;
  rozmiar: int64;
  Watek: integer;

implementation
{$R *.dfm}

procedure TMyThread.Execute;
var
  i, liczMax: Integer;
begin
  FreeOnTerminate:= True; // zwolnij po zakończeniu wątku
  liczMax:= 1;
  for i:= 0 to liczMax do
    if Assigned(fOnPostep) then
      Synchronize(DoOnPostep);
end;

procedure TMainFrm.btnStartClick(Sender: TObject);
begin
  memWatki.Clear;
  LiczbaWatkow(Sender);
end;

procedure TMainFrm.LiczbaWatkow(Sender: TObject);
var
  LiWatkow: integer;
begin
  for LiWatkow := 1 to StrToInt(edtLiczbaWatkow.Text) do
  TMyThread.Create(LiWatkow, OnPostep);
end;

constructor TMyThread.Create(Counter: Integer; OnPostep: TOnPostep = nil);
begin
  inherited Create(False);
  FCounter:= Counter;
  fOnPostep:= OnPostep;
//  FreeOnTerminate:= True; // zwolnij po zakończeniu wątku
end;

procedure TMyThread.DoOnPostep;
begin
  fOnPostep(Self, licz, liczMax);
end;

procedure TMainFrm.OnPostep(Sender: TObject; Postep, MaxPostep: Integer);
var
  licz: Integer;
  MyThread: TMyThread;
  znajdz: integer;
  i, imax: integer;
  liczplk : integer; // liczba znalezionych plikow
  Tab: array [1..10] of Integer;
  Zmienne: array [1..10] of string;
begin
  licz:=0;
    for licz:= 1 to StrToInt(edtLiczbaWatkow.Text) do
    begin
        memWatki.Clear;
        memWatki.Lines.Add('Watek ' + IntToStr(licz));
        memWatki.Lines.Add(' ');
        Watek:= licz;
        LiczPliki(Sender);
      SuspendThread(Postep);
        sleep(2000);
     ResumeThread(Postep);
    end;
end;

function RozmiarKat(dir:string):cardinal;  // obliczanie wielkości folderu łącznie z podfolderami - wyrażone w bajtach
var
  w: win32_find_data;
  f: integer;
begin
  f:=FindFirstFile(pchar(dir+'\*.*'),w);
  if f>0 then
        while FindNextFile(f,w) do
        begin
          if (w.cFileName[0]='.')and(w.cFileName='..') then continue;
          if w.dwFileAttributes and faDirectory>0 then
            RozmiarKat(dir+'\'+w.cFileName);
          Inc(rozmiar,w.nFileSizeLow);
        end;
end;

procedure TMainFrm.LiczPliki(Sender: TObject);
var
  Rec : TSearchRec;
  znajdz: integer;
  imax: integer;
  liczplk : integer; // liczba znalezionych plikow
  Tab: array [1..10] of Integer;
  nrWatek: array [1..10] of string;
begin
  liczplk:=0;
//  imax:= StrToInt(edtLiczbaWatkow.Text);
  Tab[Watek]:=Watek;
  nrWatek[Watek] := TEdit(FindComponent('edtWatek' + IntToStr(Tab[Watek]))).Text;
    begin
      znajdz := FindFirst(nrWatek[Watek] + '\*.*', faAnyFile - faDirectory, Rec); // odnajdz
      memWatki.Lines.Add(Rec.Name);
      while (znajdz = 0) do // dopoki liczba znalezionych plikow nie bedzie rowna 0
        begin
          znajdz := FindNext(Rec); // szukaj dalej
          memWatki.Lines.Add(Rec.Name);
          if (Rec.Name='.') or (Rec.Name='..') then
            begin
              continue
            end
          else Inc(liczplk);
        end;
    end;
    memWatki.Lines.Add(' ');
    memWatki.Lines.Add('Liczba plików w folderze : ' + nrWatek[Watek]);
    memWatki.Lines.Add(IntToStr(liczplk));
    FindClose(Rec); // zakoncz wyszukiwanie
end;

procedure TMainFrm.btnZamknijClick(Sender: TObject);
begin
  close
end;

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