Kilka wątków, jedna klasa

0

Witam. Piszę program w Delphi XE8, który będzie logował się na jedną stronę i wykonywał kilka różnych czynności. Chciałem żeby każda z tych czynności była wykonywana niezależnie więc postanowiłem zrobić to w wątkach. Każdy wątek potrzebuje zalogować się na stronę. Logowanie jest trochę uciążliwe i długie więc stworzyłem klasę, nazwałem ją HTTP i zapisałem w osobnym pliku *.pas
Każdy wątek tworzy klasę HTTP, odwołuje się do dwóch funkcji tej klasy, logowania i wysłania zmiennych na konkretną podstronę.
Wszystko ładnie działa dopóki aktywny jest tylko jeden wątek. Gdy aktywuję trzy wątki, dwa z nich nie mogą się zalogować.
Klasa nie korzysta z żadnych wizualnych komponentów i jest w osobnym pliku. Każdy wątek również jest w osobnym pliku i w uses ma dodany HTTP aby ładować sobie klasę. Myślałem że to skutecznie usamodzielni wątki.
I tu moje pytania. Czy kilka wątków może używać jednej klasy? Jeżeli nie to jak to rozwiązać?

Wątek w uproszczeniu:

uses
  System.Classes, System.SysUtils, System.StrUtils, Farma, HTTP, INIFiles, Vcl.Forms;

type
  TWatek = class(TThread)
  private
    zmienna1 : string;
    zmienna2 : string;
  protected
    procedure Execute; override;
  public
    constructor Create(tzmienn1, tzmienna2: string);
  end;

implementation

constructor TWatek.Create(tzmienna1, tzmienna2: string);
begin
  self.zmienna1 := tzmienna1;
  self.zmienna2 := tzmienna2;
end;


procedure TWatek.Execute;
var
  HTTP : THTTP; //Moja klasa

begin
  FreeOnTerminate := True;
  HTTP := THTTP.create();
  HTTP.loguj();
  HTTP.wyslij(link);
  HTTP.free;
exit;

Klasa w uproszczeniu

uses
  idHTTP, System.Classes, System.SysUtils, System.StrUtils, INIFiles, Vcl.Forms;

type THTTP = class
  rid : string;
  function Loguj() : boolean;
  function Wyslij(link : string) : string; overload;
  function Wyslij(link : string; parametry : string): string; overload;
private
  HTTP : TidHTTP;
  host : string;
public
  constructor Create();
  destructor Free();
end;

implementation

function DateTimeToUNIXTimeFAST(DelphiTime : TDateTime): LongWord;
begin
  Result := Round((DelphiTime - 25569) * 86400);
end;

constructor THTTP.Create;
begin
  self.HTTP := TidHTTP.Create(nil);
  HTTP.ProtocolVersion:=pv1_1;
  HTTP.HandleRedirects:=True;
end;

function THTTP.Loguj() : boolean;
var
  Parametry: TStringList;
  HTML, data, zmienne: String;
  start, koniec : integer;
  INI : TINIFile;
  login, haslo : string;

begin

//Tu jest masa kodu odpowiedzialnego za logowanie

if zalogowany = true then
	result := true
else
	result := false

exit;
0

Po pierwsze może nie ma problemu w kodzie (który swoją drogą niepotrzebnie "ocenzurowałeś", bo może nie ma czegoś istotnego) a w stronie na którą się logujesz. Jeżeli to jest ta sama strona i ten sam login to być może strona nie pozwala na na takie coś i automatycznie wylogowuje z poprzednią sesję. Sprawdź np. czy możesz jednocześnie być zalogowany w kilku przeglądarkach.
Każdy wątek może używać dowolnej ilości klas, ale jeżeli kilka wątków chce używać jednego wystąpienia klasy (jednej instancji) czyli masz utworzoną 1 klasę a np. 3 wątki chce jej używać to musi być zapewniona synchronizacja aby nie dobierały się do niej jednocześnie... ale z tego co widzę u Ciebie każdy wątek tworzy obiekt THTTP więc z tym nie powinno być problemu (przynajmniej nie widzę powodu w zamieszonym kodzie) tylko to co napisałem na początku.

0
  1. nie nazywaj zmiennych tzmienna1 - t jest dla typów
  2. nie mogą się zalogować to nie jest opis problemu! Wyskakuje błąd? Jaki?
  3. jak już @kAzek wspomniał - jeśli jest to ta sama strona to na 99% ona blokuje sesje
0
abrakadaber napisał(a):
  1. nie nazywaj zmiennych tzmienna1 - t jest dla typów
  2. nie mogą się zalogować to nie jest opis problemu! Wyskakuje błąd? Jaki?
  3. jak już @kAzek wspomniał - jeśli jest to ta sama strona to na 99% ona blokuje sesje
  1. Jak wspomniał @kAzek jest to tekst ocenzurowany. Nazw użyłem na potrzeby tekstu. poza tym nie ma to znaczenia w tym przypadku.
  2. Nie pytałem jak się zalogować. Opisałem tylko problem i pytałem o wątki i klasy więc nie rozumiem po co ta wypowiedź.
  3. Na szczęście jestem w tym jednym procencie.

Problem już rozwiązany. Strona przed logowaniem generuje unikatowy token na podstawie czasu przesyłanego w zmiennej. Token zmienia się co sekundę. Chcąc zrobić szybki program uruchamiałem trzy wątki w tym samym czasie przez co dostawały taki sam token. W efekcie tylko jeden wątek działał. A wystarczy poczekać sekundę przed uruchomieniem następnego wątku :)

Jest jeszcze jedna rzecz, która mnie zastanawia. Jak wygląda otwieranie jednego pliku przez kilka wątków? Czy jeżeli będę otwierać plik tylko do odczytu to mogę go ładować do kilku wątków? A gdy otwieram plik do zapisu to plik zajęty jest tylko przy wpisywaniu danych czy przez cały czas gdy jest otwarty? I jeszcze pliki otwierane przy pomocy TINIFile. Można otworzyć jeden plik w kilku wątkach? Jeżeli nie to czy plik zajęty jest aż nie zwolnię klasy czy tylko przy wprowadzaniu/odczytywaniu danych. Dzięki za odpowiedzi.

0

Raczej nie wolno, w nowszych wersjach Delphi można użyć TMultiReadExclusiveWriteSynchronizer a w starszych to moim zdaniem najlepiej użyć sekcji krytycznych (TCriticalSection) i kod odczytu/zapisu umieszczać właśnie w sekcji krytycznej.

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