Looking for c# Keywords? Try Ask4Keywords

C# Language Тупики (два потока, ожидающие друг друга)


пример

Тупик - это то, что происходит, когда два или более потока ожидают, что каждый может завершить или выпустить ресурс таким образом, что они будут ждать навсегда.

Типичный сценарий двух потоков, ожидающих завершения каждого из них, - это когда поток графического интерфейса Windows Forms ожидает рабочий поток, а рабочий поток пытается вызвать объект, управляемый потоком графического интерфейса пользователя. Обратите внимание, что с помощью этого кода, нажатие кнопки1 приведет к зависанию программы.

private void button1_Click(object sender, EventArgs e)
{
    Thread workerthread= new Thread(dowork);
    workerthread.Start();
    workerthread.Join();
    // Do something after
}

private void dowork()
{
    // Do something before
    textBox1.Invoke(new Action(() => textBox1.Text = "Some Text"));
    // Do something after
}

workerthread.Join() - это вызов, который блокирует вызывающий поток до тех пор, пока workthread не завершится. textBox1.Invoke(invoke_delegate) - это вызов, который блокирует вызывающий поток до тех пор, пока поток GUI не обработает invoke_delegate, но этот вызов вызывает взаимоблокировки, если поток GUI уже ожидает завершения вызова.

Чтобы обойти это, можно использовать неблокирующий способ вызова текстового поля:

private void dowork()
{
    // Do work
    textBox1.BeginInvoke(new Action(() => textBox1.Text = "Some Text"));
    // Do work that is not dependent on textBox1 being updated first
}

Однако это вызовет проблемы, если вам нужно запустить код, зависящий от первого обновляемого текстового поля. В этом случае запустите это как часть вызова, но имейте в виду, что это запустит его в потоке графического интерфейса.

private void dowork()
{
    // Do work
    textBox1.BeginInvoke(new Action(() => {
        textBox1.Text = "Some Text";
        // Do work dependent on textBox1 being updated first, 
        // start another worker thread or raise an event
    }));
    // Do work that is not dependent on textBox1 being updated first
}

В качестве альтернативы, запустите весь новый поток, и пусть это сделает ожидание в потоке графического интерфейса, так что workthread может завершиться.

private void dowork()
{
    // Do work
    Thread workerthread2 = new Thread(() =>
    {
        textBox1.Invoke(new Action(() => textBox1.Text = "Some Text"));
        // Do work dependent on textBox1 being updated first, 
        // start another worker thread or raise an event
    });
    workerthread2.Start();
    // Do work that is not dependent on textBox1 being updated first
}

Чтобы свести к минимуму риск захода в тупик взаимного ожидания, всегда избегайте циркулярных ссылок между нитями, когда это возможно. Иерархия потоков, в которых потоки нижнего уровня оставляют сообщения только для высокопоставленных потоков и никогда не ждут от них, не будут сталкиваться с такой проблемой. Однако он все равно будет уязвим для блокировок, основанных на блокировке ресурсов.