Domanda

Ho un semplice scenario produttore/consumatore, in cui viene prodotto/consumato un solo articolo.Inoltre, il produttore attende il completamento del thread di lavoro prima di continuare.Mi rendo conto che questo evita l'intero punto del multithreading, ma per favore supponi che debba davvero essere in questo modo (:

Questo codice non viene compilato, ma spero che tu abbia l'idea:

// m_data is initially null

// This could be called by any number of producer threads simultaneously
void SetData(object foo)
{
    lock(x)                      // Line A
    {
        assert(m_data == null);
        m_data = foo;
        Monitor.Pulse(x)         // Line B
        while(m_data != null)
            Monitor.Wait(x)      // Line C
    }
}

// This is only ever called by a single worker thread
void UseData()
{
    lock(x)                      // Line D
    {
        while(m_data == null)
            Monitor.Wait(x)      // Line E
        // here, do something with m_data
        m_data = null;
        Monitor.Pulse(x)         // Line F
    }
}

Ecco la situazione di cui non sono sicuro:

Supponiamo che molti thread chiamino SetData() con input diversi.Solo uno di loro entrerà nella serratura e gli altri verranno bloccati sulla linea A.Supponiamo che quello che è entrato nella serratura m_data e si dirige verso la linea C.

Domanda:Il Wait() sulla riga C potrebbe consentire a un altro thread sulla riga A di ottenere il blocco e sovrascrivere m_data prima ancora che il thread di lavoro ci arrivi?

Supponiamo che ciò non accada e che il thread di lavoro elabori l'originale m_data, e alla fine arriva alla linea F, cosa succede quando Pulse() si spegne?

Solo il thread in attesa sulla linea C sarà in grado di ottenere il blocco?Oppure competerà anche con tutti gli altri thread in attesa sulla linea A?

Essenzialmente, voglio sapere se Pulse()/Wait() comunicano tra loro appositamente "sotto il cofano" o se sono allo stesso livello con lock().

La soluzione a questi problemi, se esistono, è ovviamente ovvia: basta circondare SetData() con un altro blocco, ad esempio lock(y).Sono solo curioso di sapere se è un problema tanto per cominciare.

È stato utile?

Soluzione

Non vi è alcuna garanzia che il consumatore venga messo in coda in attesa o pronto prima di un altro produttore.
I monitor in stile C# e Java sono descritti in Wikipedia, sotto "Monitoraggio delle condizioni implicite".
Una bella panoramica di ciò che accade in Monitor (preso da Questo ottimo sito):alt text

"Il Wait() sulla riga C potrebbe consentire a un altro thread sulla riga A di ottenere il blocco e sovrascrivere m_data prima ancora che il thread di lavoro arrivi ad esso?"

Supporre che SetData() viene chiamato da due thread del produttore, P1 & P2.
Un thread di consumo, C1 è iniziato anche lui.
P1, P2 E C1 entrano tutti nella coda dei pronti.
P1 acquisisce prima il blocco.
La coda d'attesa è vuota, Pulse() SU line B non ha alcun effetto.
P1 aspetta line C, quindi viene inserito nella coda di attesa.
Il thread successivo nella coda pronta acquisisce il blocco.
Può esserlo ugualmente P2 O C1 - nel primo caso l'affermazione fallisce.
Hai una condizione di gara.

"Supponendo che ciò non accada e che il thread di lavoro elabori l'm_data originale e alla fine raggiunga la riga F, cosa succede quando Pulse() si attiva?"

Sposterà un cameriere dalla coda di attesa alla coda pronta.
Il blocco è mantenuto dal thread che emette il file Pulse().
Il thread notificato lo farà avere una possibilità per acquisire il lock dopo che il thread pulsante ha rilasciato il lock (ce ne possono essere già altri in coda pronti).
Da MSDN, Monitor.Pulse():
"Il thread che attualmente possiede il blocco sull'oggetto specificato richiama questo metodo per segnalare il thread successivo in linea per il blocco.Dopo aver ricevuto l'impulso, il thread in attesa viene spostato nella coda pronta.Quando il thread che ha invocato Pulse rilascia il lock, il thread successivo nella coda pronta (che non è necessariamente il thread che ha ricevuto l'impulso) acquisisce il lock."

"Solo il thread in attesa sulla linea C sarà in grado di ottenere il lock?Oppure competerà anche con tutti gli altri thread in attesa sulla linea A?"

Tutti i thread che si trovano nella coda pronta "competeno" per avere il blocco successivo.
Non importa se sono arrivati ​​direttamente o dalla coda d'attesa tramite Pulse().

Le "code" potrebbero essere implementate con altri mezzi.(Non il coda struttura dei dati in quanto tale).
In questo modo a Monitor l'implementazione potrebbe non garantire l'equità, ma potrebbe avere un throughput/prestazioni complessivi più elevati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top