2016-05-24 1 views
0

J'apprends Ada et j'ai quelques problèmes pour comprendre les modèles de concurrence. L'application de test suivante doit créer trois tâches qui s'exécutent en parallèle et impriment simplement une série de nombres. Si j'utilise une tâche sans entry alors tout va bien, mais si j'utilise des entrées les blocs d'appel de procédure et aucune concurrence peuvent se produire du tout. Je comprends qu'il y a une possibilité de réaliser une exclusion mutuelle et une exécution synchronisée, mais je ne suis pas capable de comprendre comment détacher les tâches afin qu'il soit même possible de créer plusieurs d'entre elles.Multithreading dans Ada

q_multithreading.ads:

package Q_MULTITHREADING is 

    task type TASK_LOOP is 
    end TASK_LOOP; 

    type TASK_LOOP_ACCESS is access TASK_LOOP; 

    --=========================================================================== 

    task type TASK_ENTRY_LOOP is 
    entry P_ITERATE(to : in Integer); 
    end TASK_ENTRY_LOOP; 

    type TASK_ENTRY_LOOP_ACCESS is access TASK_ENTRY_LOOP; 

    --=========================================================================== 

    procedure P_EXECUTE_NO_ENTRY; 

    procedure P_EXECUTE_ENTRY(to : in Integer); 

end Q_MULTITHREADING; 

q_multithreading.adb:

with Ada.Text_IO; 

package body Q_MULTITHREADING is 

    V_ID_COUNTER : Integer := 1; 

    --=========================================================================== 

    task body TASK_LOOP is 

    V_ID : Integer := -1; 

    begin 

    V_ID := V_ID_COUNTER; 
    V_ID_COUNTER := V_ID_COUNTER + 1; 

    for i in 1 .. 15 loop 
     delay 0.1; 
     Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " & 
          Integer'Image(i)); 
    end loop; 

    V_ID_COUNTER := V_ID_COUNTER - 1; 

    end TASK_LOOP; 

    --=========================================================================== 

    task body TASK_ENTRY_LOOP is 

    V_ID : Integer := -1; 

    begin 

    V_ID := V_ID_COUNTER; 
    V_ID_COUNTER := V_ID_COUNTER + 1; 

    accept P_ITERATE(to : in Integer) do 
     for i in 1 .. to loop 
     delay 0.1; 
     Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " & 
           Integer'Image(i)); 
     end loop; 
    end P_ITERATE; 

    V_ID_COUNTER := V_ID_COUNTER - 1; 

    end TASK_ENTRY_LOOP; 

    --=========================================================================== 

    procedure P_EXECUTE_NO_ENTRY is 

    V_TASK1, V_TASK2, V_TASK3 : TASK_LOOP_ACCESS; 

    begin 

    V_ID_COUNTER := 1; 

    Ada.Text_IO.Put_Line("Starting task 1 ..."); 
    V_TASK1 := new TASK_LOOP; 

    Ada.Text_IO.Put_Line("Starting task 2 ..."); 
    V_TASK2 := new TASK_LOOP; 

    Ada.Text_IO.Put_Line("Starting task 3 ..."); 
    V_TASK3 := new TASK_LOOP; 

    end P_EXECUTE_NO_ENTRY; 

    --=========================================================================== 

    procedure P_EXECUTE_ENTRY(to : in Integer) is 

    V_TASK1, V_TASK2, V_TASK3 : TASK_ENTRY_LOOP_ACCESS; 

    begin 

    V_ID_COUNTER := 1; 

    V_TASK1 := new TASK_ENTRY_LOOP; 
    Ada.Text_IO.Put_Line("Starting task 1 ..."); 
    V_TASK1.P_ITERATE(to); -- blocking 

    V_TASK2 := new TASK_ENTRY_LOOP; 
    Ada.Text_IO.Put_Line("Starting task 2 ..."); 
    V_TASK2.P_ITERATE(to - 5); -- blocking 

    V_TASK3 := new TASK_ENTRY_LOOP; 
    Ada.Text_IO.Put_Line("Starting task 3 ..."); 
    V_TASK3.P_ITERATE(to + 3); -- blocking 

    end P_EXECUTE_ENTRY; 

end Q_MULTITHREADING; 

Comme je l'ai déjà mentionné, si j'appelle P_EXECUTE_NO_ENTRY la sortie est désordonnée et les tâches sont détachées du thread principal. D'autre part *P_EXECUTE_ENTRY(to : in Integer) conduit à un appel de procédure de blocage et la sortie est comme une application qui n'utilise pas de tâches.

Comment les tâches avec des entrées sont-elles exécutées simultanément dans Ada?

De plus, dois-je également désallouer les tâches? (Des exemples provenant du Web ne l'ont pas fait)

+1

Vous n'avez pas besoin de créer des tâches avec 'new'. Vous pouvez également déclarer simplement les objets d'un type de tâche. –

Répondre

5

Quand vous dites

accept P_ITERATE(to : in Integer) do 
    for i in 1 .. to loop 
    delay 0.1; 
    Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " & 
          Integer'Image(i)); 
    end loop; 
end P_ITERATE; 

l'appelant est bloqué jusqu'à ce que le end P_ITERATE , donc la boucle complète se termine avant que P_EXECUTE_ENTRY puisse continuer à la tâche suivante.

Pour résoudre ce problème, enregistrez le nombre de boucles dans une variable de tâche et exécuter la boucle en dehors du accept:

accept P_ITERATE(to : in Integer) do 
    count := to; 
end P_ITERATE; 
for i in 1 .. count loop 
    delay 0.1; 
    Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " & 
         Integer'Image(i)); 
end loop; 

Quant à désaffecter les tâches - la plupart des programmes qui se terminent ne se souciaient pas, parce que le système d'exploitation libère la mémoire lors de la sortie du processus. Dans ce cas, vous ne vous détourneriez probablement pas avant que la tâche ne soit terminée; La désallocation d'une tâche en cours peut entraîner un comportement inattendu. Comment gérer cela devrait être une question différente, je pense.

3

Les tâches sont synchronisées pendant un rendez-vous (c'est-à-dire tant que vous êtes dans une instruction accept).

En général, vous limiter une déclaration accept à la copie des arguments passés à/de la tâche contenant la déclaration accept:

accept Start (Steps : in Positive) do 
    Count := Steps; 
end Start; 

for I in 1 .. Count loop 
    ...