Obiekty i thread safe

0

Cześć, mam pewien dylemat i chciałem się upewnić, czy dobrze myślę. Załóżmy, że mam metodę w klasie:


function TMyClass.Sum(a, b: integer): integer;
begin
  cs.Enter;
  result:=a+b;
  cs.Leave;
end;

cs to oczywiście TCriticalSection.

Mam też utworzony jeden obiekt tej klasy. Jest on używany w kilku wątkach. I teraz pytanie, czy taki zapis klasy jak wyżej wystarczy, żeby uczynić ją thread safe, czy powinienem raczej stosować sekcje na obiekt, tzn:


cs.Enter;
a:=ObjOfMyClass.Sum(1, 2);
cs.Leave;
0

To co pokazałeś jest thread safe nawet bez TCriticalSection:

function TMyClass.Sum(a, b: integer): integer;
begin
  result:=a+b;
end;

i już.

0

A możesz wyjaśnić dlaczego to jest thread safe?

0
Juhas napisał(a):

A możesz wyjaśnić dlaczego to jest thread safe?

Bo operujesz tylko na argumentach funkcji. Nie czytasz ani nie zmieniasz obiektu.

0

Aha, to teraz bardziej szczegółowo. Jest taka klasa(wersja bardzo uproszczona):

type
  TMyClass = class
  private
    FADO: TADOQuery;
  public
    function ExecuteQuery(sql: string): boolean;
end;

//i ciało
constructor Create();
  FADO:=TADOQuery.Create(nil);
end;

function ExecuteQuery(sql: string): boolean;
begin
  FADO.SQL.Text:=sql;
  try
    FADO.Execute;
    result:=true;
  except
    result:=false;
  end;
end;

Jak sprawa ma się teraz?

0

Zrób tak:

function ExecuteQuery(sql: string): boolean;
begin
          EnterCriticalSection(CritSect);
          try
            // przetwarzanie
          finally
            LeaveCriticalSection(CritSect);
          end;
end;

Przykład bez try/finally:
http://www.delphicorner.f9.co.uk/articles/op4.htm
http://edn.embarcadero.com/article/22411

Przykład dla nowszego Delphi:
http://docwiki.embarcadero.co[...]E3/en/Using_Critical_Sections

0

Znowu nie potrzebujesz CS:

type
  TMyClass = class
  private
  public
    function ExecuteQuery(sql:String):Boolean;
end;

function TMyClass.ExecuteQuery(sql:String):Boolean;
var FADO:TADOQuery;
begin
  Result:=false;
  FADO:=TADOQuery.Create(nil);
  try
    FADO.SQL.Text:=sql;
    try
      FADO.Execute;
      result:=true;
    except
    end;
  finally
    FADO.Free;
  end;
end;

I niech ADO się martwi o synchronizacje.

0

Chodzi o to, żeby nie tworzyć ADO w executeQuery, tylko w konstruktorze. Mam np. takie pętle, w których wykonuję kilka nawet tysięcy insertów i muszę znać rezultat każdego z nich. I teraz tworzyć i niszczyć kilka tysięcy razy obiekt podczas jednej pętli, to... ;)

0

I myślisz że za pomocą synchronizacji przyspieszysz? - grubo się mylisz, wręcz odwrotnie.

0
Juhas napisał(a):

Chodzi o to, żeby nie tworzyć ADO w executeQuery, tylko w konstruktorze. Mam np. takie pętle, w których wykonuję kilka nawet tysięcy insertów i muszę znać rezultat każdego z nich. I teraz tworzyć i niszczyć kilka tysięcy razy obiekt podczas jednej pętli, to... ;)

To zupełnie nie tędy droga.
Jaką masz bazę danych?
1) Poszukaj czegoś o bulk load dla swojej bazy
2) Zrób CSV z danymi które chcesz zaimportować
3) Odpal narzędzie masowego ładowania i załaduj CSV-a do tabeli importowej - pola np. VARCHAR(255)
4) W SQL-u popraw dane zaimportowane lub przekonwertuj je do tabel docelowych

Odpalanie po jednym SQL-u na rekord - w każdym środowisku - będzie wolne.

Inne rozwiązanie - jeśli to MySQL: masz np. składnie pozwalającą wpisać np. 500 rekordów jedną komendą SQL:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

http://dev.mysql.com/doc/refman/5.5/en/insert.html

Ale to raczej tylko w MySQL-u. W każdej bazie jest inaczej.

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