2016-05-24 19 views
0

Ich lerne Ada und ich habe ein paar Probleme beim Verständnis der Gleichzeitigkeitsmodelle. Die folgende Testanwendung muss 3 Aufgaben erstellen, die parallel ausgeführt werden und einfach eine Reihe von Zahlen drucken. Wenn ich eine Aufgabe ohne entry verwende, dann ist alles in Ordnung, aber wenn ich Einträge verwende, blockiert der Prozeduraufruf und es kann überhaupt keine Nebenläufigkeit passieren.Multithreading in Ada

Ich verstehe, dass es eine Möglichkeit gibt, gegenseitigen Ausschluss und synchronisierte Ausführung zu erreichen, aber ich bin nicht in der Lage zu verstehen, wie die Aufgaben gelöst werden, so dass es sogar möglich ist, mehrere von ihnen zu erstellen.

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; 

Wie schon erwähnt, wenn ich P_EXECUTE_NO_ENTRY nennen die Ausgabe ungeordnet und die Aufgaben werden von der Haupt-Thread abgelöst. Auf der anderen Seite führt *P_EXECUTE_ENTRY(to : in Integer) zu einem Blockierprozeduraufruf und die Ausgabe ist wie eine Anwendung, die keine Aufgaben verwendet.

Wie werden Aufgaben mit Einträgen in Ada gleichzeitig ausgeführt?

Muss ich die Aufgaben auch noch freigeben? (Beispiele aus dem Internet haben es nicht getan)

+1

Sie müssen keine Aufgaben mit 'new' erstellen. Sie können auch einfach Objekte eines Aufgabentyps deklarieren. –

Antwort

5

Wenn Sie

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; 

der Anrufer bis zum end P_ITERATE blockiert wird sagen:

der Regel werden Sie eine accept Anweisung Kopieren der übergebenen Argumente zu/von der Aufgabe, die accept Anweisung enthält begrenzen , so dass die gesamte Schleife abgeschlossen ist, bevor P_EXECUTE_ENTRY mit der nächsten Aufgabe fortfahren kann.

Um dies zu beheben, die Schleifenzählung in einer Task Variablen speichern und die Schleife außerhalb des accept ausführen:

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; 

Wie bei Aufheben der Zuordnung der Aufgaben - die meisten Programme, die sich nicht die Mühe, weil das Betriebssystem beenden würde gibt Speicher beim Beenden des Prozesses frei. In diesem Fall würden Sie wahrscheinlich nicht zur Freigabe wechseln, bevor die Aufgabe tatsächlich beendet wurde. Die Freigabe einer laufenden Task kann zu unerwartetem Verhalten führen. Wie man damit umgeht, sollte eine andere Frage sein, denke ich.

3

Aufgaben werden während eines Rendezvous synchronisiert (d. h. solange Sie sich in einer accept-Anweisung befinden).

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

for I in 1 .. Count loop 
    ...