Problem z równoległością wątków

0

OK, sytuacja wygląda tak. Dla ułatwienia powiedzmy, że mam 2 wątki.

Wątek główny, który zajmuje się komunikacją z klientami i wątek, w których zachodzą czasotrwałe operacje.

Scenariusz wygląda tak:
Wątek główny

  1. Klient łączy się.
  2. Klient wysyła prośbę o wykonanie jakiejś operacji.
  3. Serwer sprawdza, czy jakaś operacja nie jest już wykonywana. Jeśli jest, dodaje prośbę z punktu 2 do listy, jeśli nic nie jest wykonywane, wykonuje ją.

Wątek operacyjny:

  1. Otrzymuje zadanie, że ma wykonać jakąś operację.
  2. Ustawia flagę informującą, że trwa operacja(za pomocą Synchronize)
  3. WYkonuje operacje
  4. Ustawia flagę, że nie trwa żadna operacja(Synchronize)
  5. Czeka sekundę
  6. Sprawdza, czy ma jakieś zadania w kolejce(lista z punktu 3 scenariusza wątku głównego). Jeśli jakaś operacja jest, wykonuje ją, czyli wykonuje wszystko od punktu 1.

Teoretycznie powinno być tak, że gdy wątek operacyjny wykonuje jakąś operację, klient może się podłączyć do serwera. Tymczasem okazuje się, że nie ma tutaj równoległości.
Gdy podczas wykonywania zadania wysyłam żądanie wykonania nowego, serwer i tak najpierw czeka, aż zakończy się aktualne(nawet nie sprawdza, czy jest jakieś zadanie wykonywane).
No i jak się próbuję połączyć, gdy wykonywana jest jakaś operacja, też nie mogę.

Co to może się dziać?
Klasa wątku operacyjny jest tworzona normalnie na TThread.
Nawet nie wiem za bardzo jaki kod mam pokazać, bo wszystko wydaje się być w porządku.

0
Juhas napisał(a)
  1. Ustawia flagę informującą, że trwa operacja(za pomocą Synchronize)
  2. Ustawia flagę, że nie trwa żadna operacja(Synchronize)

że tak kulturalnie zapytam - po ch*** to synchronize? Bo chyba nie chcesz powiedzieć, że flaga jest trzymana przez wątek główny (GUI?) a nie przez wątek roboczy

Co to może się dziać?
wszystko :-/.

Klasa wątku operacyjny jest tworzona normalnie na TThread.
tzn jak?

Nawet nie wiem za bardzo jaki kod mam pokazać, bo wszystko wydaje się być w porządku.
jakby było ok to by działało. Pokaż tworzenie wątku pobocznego, ustawianie i zwalnianie flagi, odczyt czy wątek poboczny jest zajęty, a i jeszcze pokaż "kolejkę z zadaniami" - co to jak to, odczyt przez wątek roboczy i dodanie przez wątek główny

0
Misiekd napisał(a)
Juhas napisał(a)
  1. Ustawia flagę informującą, że trwa operacja(za pomocą Synchronize)
  2. Ustawia flagę, że nie trwa żadna operacja(Synchronize)

że tak kulturalnie zapytam - po ch*** to synchronize? Bo chyba nie chcesz powiedzieć, że flaga jest trzymana przez wątek główny (GUI?) a nie przez wątek roboczy

OK, aplikacja to usługa, więc właściwie nie ma GUI ;)
Flaga jest zadeklarowana w osobnym unicie.

Klasa wątku operacyjny jest tworzona normalnie na TThread.
tzn jak?

W zdarzeniu ServiceStart:

  QueueList:=TStringList.Create; {to jest tworzona kolejka, stringList, w którym trzymam nazwy procedur do wykonania}
  PluginThread:=TPluginThread.Create(true); //tworzę zatrzymany wątek
  PluginThread.CreatePluginManager; //tworzę sobie pewien obiekt w wątku
  PluginThread.Priority:=tpHigher; //myślałem, że to pomoże, ale nic nie daje
  PluginThread.Resume; //uruchamiam wątek

Pokaż tworzenie wątku pobocznego, ustawianie i zwalnianie flagi, odczyt czy wątek poboczny jest zajęty, a i jeszcze pokaż "kolejkę z zadaniami" - co to jak to, odczyt przez wątek roboczy i dodanie przez wątek główny

Tworzenie jest wyżej.
Ustawianie i zwalnianie flagi:

Wątek poboczny(analogicznie wyglądają inne procedury w tym wątku):

procedure TPluginThread.GetNewEvents;
begin
  FOIP:=true;
  Synchronize(SetOperationInProgress);

  FPluginManager.GetNewEvents;
  Synchronize(ReadQueue);
end;

Procedura SetOperationInProgress przypisuje do zmiennej PluginOperationInProgress wartość zmiennej FOIP. PluginOperationInProgress to ta flaga, która mówi, czy operacja trwa, czy nie.

ReadQueue, jak sama nazwa wskazuje odczytuje kolejkę zdarzeń:

procedure TPluginThread.ReadQueue;
var
  procName: string;
begin
  FOIP:=false;
  Synchronize(SetOperationInProgress);

  if QueueList.Count>0 then //jeśli jest coś do wykonania to wykonaj
  begin
    procName:=QueueList[0]; 
    QueueList.Delete(0);
    ExecMethod(Self, procName);
  end;
end;

Metoda ExecMethod po prostu wywołuje metodę o przekazanej nazwie.

Wątek główny - sprawdzanie zajętości wątku i dodanie operacji do kolejki:

  if PluginOperationInProgress then
    AddQueue('GetNewEvents') //po prostu dodanie stringa do TStringList
  else
    PluginThread.GetNewEvents;

Czyli: jeśli jakaś operacja jest wykonywana, dodaj do kolejki, jeśli nie, wykonaj.

0
  1. po co w ReadQueue masz Synchronize(SetOperationInProgress); - przecież ReadQueue wywołujesz przez Synchronize
  2. Jak wygląda SetOperationInProgress
  3. Jak wygląda Execute wątku
  4. co to jest PluginOperationInProgress
0
Misiekd napisał(a)
  1. po co w ReadQueue masz Synchronize(SetOperationInProgress); - przecież ReadQueue wywołujesz przez Synchronize

No myślałem, że trzeba przy wszystkim dawać, co współdzielone.

  1. Jak wygląda SetOperationInProgress

To jest po prostu zwykłe przypisanie:

PluginOperationInProgress:=FOIP;

gdzie FOIP jest zmienną prywatną w klasie wątku ustawianą w odpowiednich miejscach.

  1. Jak wygląda Execute wątku
while not terminated do
begin
  ProcessMessages;
  sleep(200);
end;

FreeAndNil(FPluginManager);
  1. co to jest PluginOperationInProgress

To jest właśnie ta współdzielona zmienna, która mówi o tym, czy wątek wykonuje aktualnie jakąś operację, czy nie.

0

Niestety wywalenie tego Synchronize nic nie dało. Temat więc nadal otwarty.

Czy to może być coś związanego z tym, że w tym osobnym wątku wykonuję różne operacje na pluginach(pliki dll), które łączą się z bazą danych? Wątek główny też ma połączenie z tą samą bazą danych.

0

Miałem kiedys duzy problem bo byłem zmuszony korzystać z bazy przez wątki. Jeśli chodzi o baze Firebird w kwestii równoległego dostępu wątków do bazy bardzo pomógł mi TIbConnectionBroker. Zarządza dostępem i dopuszcza wątki po kolei. Ustawiasz maksymalną liczbę równoczesnych połączeń i działasz. Połączenie z bazą powołujesz przy Create wątku IbConnectionBroker.GetConnection) a zwalniasz na koniec wątku IBConnectionBroker1.ReleaseConnection

0

OK, a jeśli chodzi o MSSQL 2005 Express? ;>

0

nie pracowałem nad nim, ale jeśli taki mechanizm istnieje dla darmowego teraz i opensourcowego Firebirda to dla najczęściej płatnych serwerów Microsofta na pewno wymyślono coś podobnego

0

No właśnie szukałem w necie pod tym kątem i nic nie znalazłem. Dodatkowo dalej nie mam pewności, czy to na pewno wina serwera.

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