Utilisation de TTask de la bibliothèque de programmation parallèle
Remonter à Utilisation de la bibliothèque de programmation parallèle
La bibliothèque de programmation parallèle fournit une classe TTask pour exécuter une ou plusieurs tâches en parallèle. Une tâche est une unité de travail à effectuer. La PPL fait l'association entre la tâche et le thread qui effectue la tâche, de sorte que vous pouvez exécuter plusieurs tâches en parallèle sans avoir à créer vos propres threads personnalisés ni à les gérer.
TTask crée et gère l'interaction avec des instances de ITask. ITask est une interface qui fournit un ensemble de méthodes et de propriétés pour démarrer, attendre, annuler et aussi une propriété pour l'état (Created, WaitingToRun, Running, Completed, WaitingForChildren, Canceled, Exception).
Exécution d'une tâche en arrière-plan
Une fonctionnalité de TTask consiste à empêcher le verrouillage de l'interface utilisateur lorsque vous voulez démarrer quelque chose en arrière-plan. L'exemple de code suivant montre comme exécuter une seule tâche et la démarrer :
Delphi :
procedure TForm1.Button1Click(Sender: TObject);
var
aTask: ITask;
begin
aTask := TTask.Create(
procedure
begin
sleep (3000); // 3 seconds
TThread.Synchronize(TThread.Current,
procedure
begin
ShowMessage ('Hello');
end);
end);
aTask.Start;
end;
C++ :
Si vous utilisez un compilateur C++ amélioré par Clang, vous pouvez utiliser les expressions lambda :
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_ITask task = TTask::Create([&](){
Sleep(3000);
ShowMessage("Hello");
});
task->Start();
}
Pour les compilateurs C++, vous pouvez déclarer une sous-classe TProc et en utiliser une instance transtypée en _di_TProc
:
class TCppTask : public TCppInterfacedObject<TProc> {
public:
void __fastcall Invoke() {
Sleep(3000);
ShowMessage("Hello");
}
};
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_ITask task = TTask::Create(_di_TProc(new TCppTask()));
task->Start();
}
Attente de la terminaison des tâches
TTask fournit WaitForAll et WaitForAny pour attendre la fin de toutes les tâches ou d'une tâche. WaitForAll renvoie le résultat lorsque toutes les tâches sont terminées, tandis que WaitForAny vous indique que la première tâche est terminée. Par exemple, si vous avez deux tâches A et B qui durent respectivement 3 et 5 secondes, le temps d'attente avant d'obtenir un résultat est :
- Séquentiellement (sans utiliser TTask/ITask) = 8 secondes
- TTask.WaitForAny = 3 secondes
- TTask.WaitForAll = 5 secondes
L'exemple suivant utilise la méthode WaitForAll method:
Delphi :
procedure TForm1.MyButtonClick(Sender: TObject);
var
tasks: array of ITask;
value: Integer;
begin
Setlength (tasks ,2);
value := 0;
tasks[0] := TTask.Create (procedure ()
begin
sleep(3000);
TInterlocked.Add (value, 3000);
end);
tasks[0].Start;
tasks[1] := TTask.Create (procedure ()
begin
sleep (5000);
TInterlocked.Add (value, 5000);
end);
tasks[1].Start;
TTask.WaitForAll(tasks);
ShowMessage ('All done: ' + value.ToString);
end;
C++ :
Si vous utilisez un compilateur C++ amélioré par Clang, vous pouvez utiliser les expressions lambda :
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_ITask tasks[2];
int value = 0;
tasks[0] = TTask::Create([&](){
Sleep(3000);
TInterlocked::Add(value, 3000);
});
tasks[0]->Start();
tasks[1] = TTask::Create([&](){
Sleep(5000);
TInterlocked::Add(value, 5000);
});
tasks[1]->Start();
TTask::WaitForAll(tasks, sizeof(tasks)/sizeof(tasks[0])-1);
ShowMessage("All done! " + IntToStr(value));
}
Pour les compilateurs C++, vous pouvez déclarer une sous-classe TProc et en utiliser une instance transtypée en _di_TProc
:
class TCppTask : public TCppInterfacedObject<TProc> {
public:
TCppTask(int &value, int increase) : m_value(value), m_increase(increase) {}
void __fastcall Invoke() {
Sleep(m_increase);
TInterlocked::Add(m_value, m_increase);
}
protected:
int& m_value;
int m_increase;
};
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_ITask tasks[2];
int value = 0;
tasks[0] = TTask::Create(_di_TProc(new TCppTask(value, 3000)));
tasks[0]->Start();
tasks[1] = TTask::Create(_di_TProc(new TCppTask(value, 5000)));
tasks[1]->Start();
TTask::WaitForAll(tasks,(sizeof(tasks)/sizeof(tasks[0])-1));
ShowMessage("All done! " + IntToStr(value));
}