Quali rappresentazioni intermedie possono essere utilizzate per ragionare sulla concorrenza?


12

Sto cercando di capire meglio cosa sarebbe necessario per un compilatore per poter fare scelte intelligenti in merito alla concorrenza per conto del programmatore. Mi rendo conto che ci sono molti aspetti difficili di questo problema, ad esempio:

  • Garantire che non ci siano condizioni di gara
  • Garantire che il codice da eseguire contemporaneamente non abbia effetti collaterali che incidono sul significato semantico del codice

  • Decidere se vale l'overhead derivante dalla rotazione dei thread, dato il grado di parallelismo disponibile nel codice

La mia comprensione è che le due principali rappresentazioni intermedie utilizzate nei compilatori moderni sono assegnazioni singole statiche per linguaggi procedurali e orientati agli oggetti e continuazioni che passano di stile per linguaggi funzionali. Ragionare su uno dei problemi sopra elencati sembra difficile usando queste forme intermedie. Anche i linguaggi che dovrebbero teoricamente avere le migliori possibilità di parallelizzazione automatica (linguaggi funzionali puri come Haskell con una garanzia di assenza di effetti collaterali) hanno compiuto progressi limitati su questo fronte.

Quindi la mia domanda è davvero quali rappresentazioni intermedie sono state usate per cercare di affrontare questo problema? Ci sono altre rappresentazioni che sono state utilizzate nella ricerca accademica di cui non sono a conoscenza e che sono più adatte a questo compito? Questo problema deve essere sostanzialmente risolto dal front-end del compilatore manipolando l'albero di sintassi astratto prima che la compilazione raggiunga una rappresentazione intermedia?


Se scrivi il tuo codice in modo funzionale, non dovrai preoccuparti delle condizioni di gara o degli effetti collaterali.
Robert Harvey,

4
Questo non risponde perfettamente alla tua domanda, ma potresti essere interessato a Process Calculi che può essere utilizzato per ragionare sul codice simultaneo. L'esempio più noto potrebbe essere il calcolo Pi . Tuttavia, la parallelizzazione automatica è ancora un problema in gran parte irrisolto e meglio affrontato progettando linguaggi specificamente per fornire al compilatore determinate garanzie o usando annotazioni speciali.
amon,

4
L' articolo che fa da sfondo a Intel Concurrent Collections (CnC) elenca otto modelli simultanei fondamentali, come Producer-Consumer. Questi modelli concorrenti a loro volta dipendono da una serie di proprietà, come l'immutabilità e prive di effetti collaterali. (Gradirei se qualcuno potesse sintetizzare quel documento e pubblicare qui come risposta.)
rwong

Uno degli strumenti teorici si chiama "Dynamic Single Assignment (DSA)", costruito sopra SSA.
rwong

@rwong: puoi fornire un riferimento esplicito?
Ira Baxter,

Risposte:


5

Si potrebbe presumere che la concorrenza della modellazione esplicita nella rappresentazione intermedia (IR) fosse un requisito necessario. Quindi una risposta sarebbe: "qualsiasi IR utilizzato per programmi sequenziali con l'aggiunta di alcune operazioni di concorrenza", ad esempio "fork and join", "parallel x y". L'aggiunta di questi rende possibile ragionare su alcuni tipi di concorrenza, ma non necessariamente facilmente. Né è ovvio come garantire determinate proprietà (libertà dei dati) senza arrivare fino a una rappresentazione pienamente funzionale (che rende difficile modellare utilmente il parallelismo).

Probabilmente reti di Petri colorate (CPN) sono una buona scelta per rappresentare programmi con concorrenza. (I token nei CPN sono "colorati" [hanno un tipo] e possono contenere valori; "le transizioni" verso gli stati possono eseguire l'aritmetica arbitraria sui token in arrivo per produrre un token possibilmente di colore diverso con valore calcolato nel "posto"). Se si considerano i luoghi come risultati calcolati e le transizioni come operatori di modellazione (incluso uno speciale per accedere alla memoria), ciò fornisce ciò che equivale a un diagramma del flusso di dati con cui modellare i programmi. Puoi facilmente usarlo per dare un'interpretazione formale alle rappresentazioni classiche del compilatore come triple [operatore, input1, input2, output].

Esistono molti strumenti per analizzare tali grafici CPN, tra cui proprietà di calcolo come deadlock-freeness, limitatezza dei conteggi di token in luoghi, ecc. I CPN gerarchici consentono di modellare funzioni e procedure e la nozione di "chiamate".

Ciò che queste rappresentazioni non fanno chiaramente è rendere facile ragionare su dove si potrebbe parallelizzare un'applicazione. In sostanza, due sottocomputer possono essere parallele se non incidono su nessun operando condiviso (motivo per cui alcune persone adorano i programmi / le rappresentazioni funzionali). Se la rappresentazione del tuo programma modella una memoria condivisa, puoi modellarla come monolito e ottenere la solita serie di problemi sul ragionamento sulle interazioni sulla memoria condivisa, incluso l'indirizzamento aliasato, ecc. Un modo per evitare ciò è di trattare la memoria come blocchi isolati con lo stato del programma più ampio è un assemblaggio (simile ad un albero) di questi; puoi discutibilmente passare questi pezzi nella tua rappresentazione intermedia. Non esiste interazione tra due calcoli paralleli se non condividono blocchi (ad es. Sottotitoli di memoria).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.