2012-02-06 28 views
8

Sto costantemente leggendo da un file mappato in memoria un altro processo sta scrivendo e uso un mutex per sincronizzare questa operazione. Nei miei pochi test finora funziona perfettamente, ma ... cosa succede se la mia applicazione si blocca subito dopo aver acquisito il mutex e prima di rilasciarlo? C'è un modo per garantire un rilascio del mutex, anche in caso di un tale incidente?Gestione "sicura" di un Mutex?

Inoltre, come gestirò un arresto anomalo dell'altro processo, che potrebbe non aver ancora rilasciato il mutex? Devo gestire AbandonedMutexException ogni volta che chiamo mutex.WaitOne()?

In questo momento sto facendo simile a questo:

public MyState GetState() 
{ 
    MyState state = new State(); 
    this._mutex.WaitOne(); 
    try 
    { 
     state.X = this._mmView.ReadSingle(0); 
     state.Y = this._mmView.ReadSingle(4); 
     [..] 
    } 
    finally 
    { 
     this._mutex.ReleaseMutex(); 
    } 
    return state; 
} 

_mmView è un MemoryMappedViewAccessor ho un'istanza prima. L'intero metodo GetState() viene chiamato ogni frame come parte di un ciclo di gioco, quindi circa ogni millisecondo.

PS: Inoltre, c'è qualche altro ovvio problema perché questo potrebbe fallire, che non ho già menzionato?

risposta

11

risposta di Eugen è corretto - il sistema operativo rilascerà il mutex per voi. Ora riflettere su quali sono le conseguenze di questo fatto sono:

  • si tirò fuori il mutex per garantire che nessuno sarebbe stato mutare mentre stavi leggendo, o leggere lo stato mentre si stavano mutando. Supponiamo che quest'ultimo.
  • Un'altra applicazione desidera leggere lo stato, quindi tenta di assumere il mutex. È costretto ad aspettare.
  • Hai mutato qualche stato e poi si è bloccato.
  • Il sistema operativo ha rilasciato il mutex.
  • L'altra applicazione ora acquisisce immediatamente il mutex, e ora sta effettivamente leggendo lo stato "mentre" un altro processo lo sta mutando. Il fatto che l'altro processo sia ora morto e morto significa che lo stato fasullo ora durerà per sempre e il processo di lettura probabilmente si bloccherà e morirà in modo orribile. Hai appena sconfitto il sistema di sicurezza fornito dal mutex.

In breve, ti stai preoccupando esattamente della cosa sbagliata. Non dovresti preoccuparti di cosa succede se il mio mutex non viene mai rilasciato. La cosa peggiore che succede poi è che tutti aspettano per sempre, il che è triste, ma alla fine l'utente riavvierà la macchina. Dovresti essere preoccupato per cosa succede se il mutex viene rilasciato perché mi sono bloccato a metà della mutazione. In tale scenario, i processi ora si bloccheranno in modo irreversibile e i dati dell'utente saranno permanentemente danneggiati.

Non entrare in quella situazione, in primo luogo.La soluzione al problema è non arrestarsi in modo anomalo quando si è rimosso un mutex per scrivere. Se non scrivi programmi che si bloccano, non ti devi preoccupare perché non succederà. Quindi, non scrivere programmi che si bloccano mai.

+3

"non scrivere programmi che si bloccano mai" o, come ha detto il maestro Zen, "Evita errori". Ottimo consiglio. ahem. – mickeyf

+1

Tuttavia, non sembra molto robusto né realistico. Cosa succede se l'utente semplicemente uccide il processo tramite il task manager, bloccando forzatamente l'app? – Mario

+7

@ Mario: Non so cosa pensi non sia realistico; Ti assicuro che questi tipi di bug di corruzione dei dati vengono rilevati frequentemente e devono essere protetti se ti interessa lo stato dei dati dell'utente. Ri: cosa succede se l'utente si blocca l'applicazione? Mi stai chiedendo cosa succede quando l'utente fa cose che corrompono i propri dati? ** I loro dati vengono corrotti **, ecco cosa. Gli utenti che non vogliono che i loro dati siano corrotti ** non dovrebbero prendere in giro le loro app **. C'è un * motivo * per cui così facendo si apre una finestra di dialogo che dice "potresti corrompere i tuoi dati se lo fai". –

2

Quando un processo termina mentre si possiede un mutex, il sistema operativo rilascerà automaticamente il mutex per te. Prova questo acquisendo il mutex e poi raise new WhateverException() - l'altro processo continuerà.

Lo stesso vale per tutte le primitive di sincronizzazione per quanto ne so