Es trata de un error en la cuenta de .NET monitor / cerradura o no MessageBox.Show comporta de manera diferente?

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

  •  06-09-2019
  •  | 
  •  

Pregunta

Imagine que tiene dos botones en el formulario de victoria. ¿Qué cree que debería ser el comportamiento cuando el usuario presiona el botón "1" con el código de abajo?

En caso de que se vea toda la caja 5 de mensajes de una sola vez, o uno por uno - declaración MessageBox.Show está dentro de una instrucción lock?

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");
            }
        }
    }
}

Ahora bien, si sustituimos MessageBox.Show con cualquier otro DECLARACIÓN, sería ejecutar la instrucción sólo uno a la vez, los otros hilos esperarían, uno a la vez.

¿Fue útil?

Solución

Dado que se ejecuta su estado de bloqueo cuando InvokeRequired es falsa, las cerraduras se ejecutan en el mismo hilo (principal). Por lo tanto, las cerraduras no bloquearán.

Si desea que el cuadro de mensaje para bloquear, utilice ShowDialog lugar.

Otros consejos

  1. Sólo bloqueo bloquea si otro hilo posee el bloqueo, el bloqueo sobre el mismo objeto desde el mismo hilo varias veces se le permite - de lo contrario sería un callejón sin salida instantánea, después de todo, habría estado bloqueando el flujo actual a la espera para el subproceso actual.

  2. Control.BeginInvoke no ejecuta código en un subproceso diferente, siempre va a ejecutar el código en el hilo de bombeo de mensajes para el control, lo hace mediante la publicación de un mensaje a la cola de entrada del control y luego la ejecución de la código cuando llega el mensaje.

2 debido a su código no está multi-hilo en absoluto, todo lo que se ejecuta en el mismo hilo -. Y esto nos lleva de nuevo a 1, cuando usted no tiene bloqueo de múltiples hilos no hace nada

Sospecho que el hilo de interfaz de usuario es el bombeo de mensajes durante el ciclo de vida de mensaje. Debido a que las cerraduras son re-entrante (y el hilo de interfaz de usuario se está ejecutando el código cada vez), esto hace que el anterior. Tal vez tratar de pasar el propietario (this) en el cuadro de mensaje? (Voy a tratar en un segundo ...) .

Se podría bloquearlo con más fuerza, pero que bloqueará la pintura ( "no responde", etc).

Estoy de acuerdo con Nir. Después de cambiar la función para la que está debajo, se puede comprobar que se está ejecutando en el mismo hilo (como es lógico):

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);
        }
    }
}

Así que aquí porque el hilo de interfaz de usuario se debe al bloqueo, no se bloquean. La conclusión es que los subprocesos STA no son compatibles con la programación multihilo adecuada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top