Problema di multithreading C # con classe Monitor - possibile blocco vitale?
-
22-07-2019 - |
Domanda
Ho un po 'di codice, che non riesco a capire correttamente. Il problema è che il programma è multithread e all'interno c'è un po 'di codice che dovrebbe essere sincronizzato, quindi ho scritto questo:
lock (lockObject)
{
if (!Monitor.TryEnter(lockObject))
Monitor.Wait(lockObject);
//do stuff...
Monitor.PulseAll(lockObject);
}
Monitor.Exit(lockObject);
il problema che ho è che in un certo momento tutti i thread sembrano dormire - qualcuno può dire perché? Il programma continua a funzionare all'infinito consumando quasi nessun CPU, ma non viene fatto alcun lavoro - quando ho rintracciato il programma ho scoperto che ad un certo punto nessun thread è attivo ma molti di loro stanno dormendo. So che l'errore principalmente (nel caso di uno sviluppatore - sempre) si trova 0,5 m davanti al monitor - ma non riesco a capirlo da solo ... forse in pochi minuti;)
qualcuno può spiegarmelo, grazie in anticipo.
Soluzione
C'è una differenza tra LockObject
e lockObject
? Non è chiaro ...
Tuttavia! Se sono oggetti diversi, prima di tutto: non puoi Wait
su un lucchetto che non hai ... e TryEnter
restituirà false solo se specifichi un tempo scaduto. Che cosa sta esattamente cercando di fare quel codice?
Senza più contesto, non è del tutto chiaro cosa siano progettati per fare PulseAll
e Wait
; ad esempio, qui vengono utilizzati per bloccare la coda quando è troppo pieno ( Wait
) o rilascialo quando lo spazio diventa disponibile ( PulseAll
), ecc. È difficile eseguire il debug del codice di threading senza le interazioni complete tra thread.
Sembra che potresti semplicemente aver bisogno:
lock (lockObject)
{
// do stuff
}
Ci sono due problemi immediati che posso vedere; in primo luogo, non è ovvio che rilasci sempre i blocchi che prendi (cioè le eccezioni). Prova a usare lock
per Enter / Exit
- funzionerà correttamente.
In secondo luogo; se tutti i thread chiamano Wait
... chi li sveglierà? Cosa stanno aspettando ? Come presentato: sì, dormiranno tutti indefinitamente.
Altri suggerimenti
Sto supponendo che la prima istruzione di blocco sia un refuso e intendevi lock (lockObject) (lettere minuscole).
Penso che tu abbia frainteso le serrature un po 'qui. Il blocco if nel tuo codice non sarà mai vero. Il motivo è che quel lock (lockObject) si estende effettivamente al seguente
Monitor.Enter(lockObject);
try {
...
} finally{
Monitor.Exit(lockObject);
Quindi quando premi il blocco if possiedi già il blocco e TryEnter dovrebbe sempre riuscire.
Questa è una strana configurazione. "LockObject" è uguale a "lockObject"? O è un errore di battitura? Se sono uguali, la configurazione è ridondante, in quanto non è necessario chiamare Monitor.Prova Inserire qualcosa che si sta già bloccando. Se "LockObject" è un oggetto diverso, perché non spostare Monitor.Exit all'interno dell'istruzione lock?