2013-07-06 7 views
10

Disclaimer: Questo può essere fatto facilmente utilizzando un MVar() come un mutex semplice. Sono solo curioso di vedere se può essere fatto con STM.Questo può essere fatto con STM?

voglio fare quanto segue atomicamente:

  • Leggi alcune variabili.

  • Decidere quale I/O eseguire, in base a ciò che ho appena letto.

  • Eseguire l'I/O.

  • Registrare i risultati nelle variabili.

Per concretezza, supponiamo che io voglio tenere traccia del numero di byte di ingresso che ho letto, e fingo ho raggiunto EOF dopo un certo numero di byte è stato consumato. (OK, lasciare che due thread leggano dallo stesso file contemporaneamente è probabilmente una cosa fasulla da fare in primo luogo, ma vieni con me su questo ...)

Chiaramente questo non può essere una singola transazione STM; c'è l'I/O nel mezzo. Chiaramente sarebbe anche sbagliato averlo come due transazioni non connesse. (Due thread potrebbero vedere che rimane un solo byte di quota ed entrambi decidono di leggere quel byte)

C'è una bella soluzione a questo problema? O STM è semplicemente lo strumento sbagliato per questo compito?

+0

Questo ti dà quello che ti serve? Il "barbiere" potrebbe essere il tuo puntatore di lettura. http://stackoverflow.com/questions/16933678/are-tchan-writes-integrated-into-haskell-stm –

+0

@DaxFohl Bene, puoi _utilizzare STM per inviare tutte le richieste di I/O a un singolo thread tramite un 'TChan "... che dovrebbe funzionare. – MathematicalOrchid

+0

Sembra che tu abbia un caso d'uso standard per la soluzione modello di base in stile Erlang, che è ciò che la cosa del barbiere implementa tramite 'STM' e' TChan'. –

risposta

1

Direi che STM non può farlo, ed è apposta. Un pezzo di codice STM può essere riavviato più volte in vari punti se una transazione viene ripristinata. Che cosa accadrebbe se esegui la transazione, esegua l'azione I/O e poi esegua il rollback quando registra i risultati nelle variabili?

Per questo motivo i calcoli STM devono essere puri, solo con l'aggiunta di primitive STM come variabili mutabili STM e matrici.

+0

Certamente non avrebbe senso eseguire I/O all'interno di una transazione; non è possibile annullare I/O. Ma le transazioni possono essere utilizzate per ottenere l'esclusione reciproca? Ed è ragionevole farlo? – MathematicalOrchid

+0

@MathematicalOrchid Per quanto ne so, l'esclusione reciproca non può essere eseguita in STM. Non ci sono garanzie che un framework STM possa attendere qualsiasi cosa - può anche ripetere una transazione fallita più e più volte in un ciclo fino a quando non riesce. Da [i documenti] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/GHC-Conc-Sync.html#v:retry): * L'implementazione potrebbe bloccare il thread fino a uno dei TVars da cui è stato letto è stato aggiornato. * Probabilmente la soluzione migliore è nella risposta data da _comonad_ - a quanto ho capito, esegue azioni 'IO' su un commit riuscito. –

+0

@MathematicalOrchid Solo un pensiero, è possibile raggiungere sia l'esclusività reciproca che la componibilità senza rischiare un deadlock? –

6

Utilizzare un TVar Bool denominato consistent per tenere traccia di se l'azione IO è in corso. Prima di eseguire l'azione IO, impostare coerente su False e dopo aver eseguito l'azione IO, impostare consistent su True. Quindi, qualsiasi azione che dipende dai valori di quelle variabili STM che si sta modificando solo mette questa clausola all'inizio:

do b <- readTVar consistent 
    check b 
    ... 

Questo assicura che quelle azioni vedere solo una visione coerente delle variabili essere modificato e non verrà eseguire mentre è in corso l'azione IO.

+0

Questo ha un sapore. Attualmente il problema che sto colpendo è che un'azione mutex non può eseguire altre azioni mutex, perché il mutex è già stato preso. Non sono sicuro se l'approccio sopra risolverà questo problema ... – MathematicalOrchid

+0

Puoi chiarire il problema del mutex? –

+0

Se si utilizza 'MVar()' come un mutex e si inizia ogni funzione con 'takeMVar', una funzione non può chiamarne un'altra poiché il mutex è già in uso. Le funzioni diventano non componibili. – MathematicalOrchid

4

Penso che stiate cercando il pacchetto stm-io-hooks.

Qualunque cosa tu voglia realmente fare - sarebbe possibile esprimerlo in termini di semantica di stop/ripetizione di STM? In altre parole: puoi eseguire un rollback e ripetere l'azione IO? In caso contrario, mi riferisco alla risposta di Gabriel Gonzalez.

+0

Bene, tutte le operazioni di I/O sono operazioni _read_, quindi l'unica cosa che modificano è lo stato di un handle. Se potessi garantire che non si verifichino due operazioni di I/O contemporaneamente, e che ognuno cerchi sempre nel posto giusto per primo ... potrebbe forse funzionare ... Ma penso che mantenere le transazioni I/O funzionerebbe meglio . – MathematicalOrchid

+1

@MathematicalOrchid: In tal caso, utilizzerei semplicemente Handle diversi. Se questa non è un'opzione, dovresti usare un meccanismo di blocco (MVar o la risposta di Gabriel) per cercare + leggere. – comonad

+0

@MathematicalOrchid: Non sono sicuro di cosa abbiate bisogno di STM, ma forse state solo sperimentando la concorrenza. Non hai bisogno di Mutex come nelle lingue inferiori: in Haskell applichi il meccanismo di blocco direttamente alla risorsa, come "Manovella MVar" invece di "(MVar(), Gestisci)". STM è un modo completamente diverso di risolvere problemi di concorrenza, utilizza "Transazioni" che possono essere interrotte/ripristinate/ripetute come una transazione monetaria tra conti bancari. Non ne vedo alcun uso per la lettura di file immutabili. – comonad