Jest to dość łatwe do zrobienia przy użyciu AsyncCalls. Załóżmy, że Twój kod niegwintowane wygląda (pomijając wszystko obsługę błędów):
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
MyLabel.Text := SqlRow[0];
...Go on to do other things...
Gdzie druga linia jest blokowanie (oczekiwanie na serwer odpowiedzieć). Nowy kod będzie wyglądać następująco:
uses AsyncCalls; //added to your existing uses statement
...
procedure DoesSomething();
var Thread: TAsyncCall; //your interface to AsyncCalls
procedure AsyncSqlCall(); //this is a LOCAL procedure
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
EnterMainThread;
try
Assert(GetCurrentThreadId = MainThreadId);
MyLabel.Text := SqlRow[0];
finally
LeaveMainThread;
end;
begin //this begins proc DoSomething()
...
Thread := LocalAsyncCall(@AsyncSqlCall);
...Go on to do other things...
end;
Wszystko zrobiliśmy jest umieścić blokowania połączeń SQL w lokalnej proc i powiedział AsyncCalls wykonać go w innym wątku, podczas gdy główny wątek kontynuuje wykonywanie. Jedyną trudną częścią było użycie VCL, który nie jest bezpieczny dla wątków. Miałem więc bezpieczną linię w głównym wątku.
Jeśli w pewnym momencie trzeba być pewien wątek asynchroniczny został zakończony, należy wykonać tę linię do zablokowania głównego wątku do AsyncSqlCall kończy:
Thread.sync;
Naprawdę miłą rzeczą jest to, że AsyncCalls obsługuje wszystkie rzeczy dotyczące tworzenia puli wątków, tworzenia wątków itp. Chociaż nie pokazano tego w tym przykładzie, możesz przekazać zmienne do wątku i zwrócić wartość. Nie musisz używać lokalnego procesu, ale dzięki temu uzyskujesz dostęp do wszystkich lokalnych zmiennych. Możesz zrobić to wszystko globalnie, a następnie uruchomić wątek Async w jednej procedurze i przetestować jego zakończenie w innym.
Ograniczenia:
Twój wątek asynchroniczny nie może dotykać (odczyt lub zapis) niczego poza własnymi zmiennymi, a główny wątek nie wolno ich dotykać, podczas gdy nitka asynchroniczny pracuje. TY musisz zakodować to w ten sposób. Nic nie powstrzyma cię od stworzenia totalnego chaosu. W powyższym przykładzie twój główny wątek nie może dotykać Query, SqlConnection, SqlResult i SqlRow. Jeśli jakakolwiek część twojego kodu użyła jednej z tych zmiennych przed wywołaniem Thread.sync, twój kod by zadziałał - ale wyrzuć wyjątki w dziwnych miejscach, których się nie spodziewałeś. Tak więc zachowaj to proste.
Twój wątek Async nie może używać VCL. Powyższy przykład pokazuje jeden z kilku sposobów bezpiecznego obejścia tego ograniczenia.
Wreszcie:
AsyncCalls nie jest pełna framework Multi-Threading. Jest to tylko sposób asynchronicznego wywoływania funkcji procs & (tj. Bez czekania). Nie próbuj przesuwać go zbyt daleko - przez co rozumiem, nie próbuj uczynić go podstawą w pełni wielozadaniowego programu.
Usunąłem tag pthread, ponieważ nie jest on kompatybilny z tagiem delphi. – mghie