È questo è un bug nella dichiarazione .net Monitor / lock o se MessageBox.Show comporta in modo diverso?

StackOverflow https://stackoverflow.com/questions/585535

  •  06-09-2019
  •  | 
  •  

Domanda

Immaginate di avere due pulsanti del modulo vittoria. Cosa pensi dovrebbe essere il comportamento quando l'utente preme il tasto "1" con il codice qui sotto?

Nel caso in cui visualizzare tutti i box 5 messaggio in un colpo solo, o uno per uno - dichiarazione MessageBox.Show si trova all'interno di una dichiarazione di blocco?

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private static readonly object lockobject = new object();

    private void button1_Click(object sender, EventArgs e)
    {
        var action = new Action(function);
        for(int i = 0; i< 5; i++)
        {
            action.BeginInvoke(null, null);
        }
    }

    private void function()
    {
        if (button2.InvokeRequired)
        {
            var func = new Action(function);
            button2.Invoke(func);
        }
        else
        {
            lock (lockobject)
            {
                MessageBox.Show("Testing");
            }
        }
    }
}

Ora, se sostituiamo MessageBox.Show con qualsiasi altro statment, sarebbe eseguire l'istruzione solo uno alla volta, gli altri thread avrebbero atteso, una alla volta.

È stato utile?

Soluzione

Dal momento che la sua dichiarazione di blocco viene eseguito quando InvokeRequired è falsa, le serrature saranno tutti eseguiti sullo stesso thread (principale). Pertanto le serrature non bloccherà.

Se si desidera che il MessageBox per bloccare, utilizzare ShowDialog invece.

Altri suggerimenti

  1. serratura blocca solo se un altro thread proprietario del blocco, il blocco sullo stesso oggetto dal medesimo filo più volte è consentito - altrimenti sarebbe un deadlock istante, dopo tutto sarebbe stato bloccando il thread corrente durante l'attesa per il thread corrente.

  2. Control.BeginInvoke non esegue il codice in un thread diverso, sarà sempre eseguire il codice nel thread di pompaggio messaggi per il controllo, lo fa inviando un messaggio alla coda di input del controllo e quindi l'esecuzione della codice quando il messaggio arriva.

a causa di 2 il codice non è multi-thread a tutti, tutto viene eseguito nello stesso thread -. E questo ci riporta a 1, quando non si dispone di più thread si bloccano non fa nulla

Ho il sospetto che il thread dell'interfaccia utente sta pompando messaggi durante il ciclo di vita MessageBox. Poiché i blocchi sono rientranti (e thread dell'interfaccia utente esegue il codice ogni volta), questo provoca il sopra. Forse provare passando il proprietario (this) nel messaggio-box? (Cercherò in un secondo ...) .

Si potrebbe bloccarlo con più forza, ma che possa bloccare la pittura ( "non risponde", ecc).

Sono d'accordo con Nir. Dopo aver modificato la vostra funzione a quello qui sotto, è possibile verificare che sia in esecuzione sullo stesso thread (non a caso):

private void function()
{
   if (button2.InvokeRequired)
   {
        var func = new Action(function);
        button2.Invoke(func);
   }
   else
   {
        lock (lockobject)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            MessageBox.Show("Testing. Running on thread "+threadId);
        }
    }
}

Quindi, ecco perché il tuo thread dell'interfaccia utente è dovuta la serratura, non ottiene bloccato. La conclusione è che thread STA non sono compatibili con il corretto programmazione multithread.

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