Looking for c# Keywords? Try Ask4Keywords

C# Language Тупики (удерживайте ресурс и подождите)


пример

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

Если thread1 удерживает блокировку на ресурсе A и ожидает, пока ресурс B будет выпущен, а thread2 будет содержать ресурс B и ожидает освобождения ресурса A, они блокируются.

Нажатие кнопки1 для следующего примера кода приведет к тому, что ваше приложение войдет в вышеупомянутое тупиковое состояние и повесит

private void button_Click(object sender, EventArgs e)
{
    DeadlockWorkers workers = new DeadlockWorkers();
    workers.StartThreads();
    textBox.Text = workers.GetResult();
}

private class DeadlockWorkers
{
    Thread thread1, thread2;

    object resourceA = new object();
    object resourceB = new object();

    string output;

    public void StartThreads()
    {
        thread1 = new Thread(Thread1DoWork);
        thread2 = new Thread(Thread2DoWork);
        thread1.Start();
        thread2.Start();
    }

    public string GetResult()
    {
        thread1.Join();
        thread2.Join();
        return output;
    }

    public void Thread1DoWork()
    {
        Thread.Sleep(100);
        lock (resourceA)
        {
            Thread.Sleep(100);
            lock (resourceB)
            {
                output += "T1#";
            }
        }
    }

    public void Thread2DoWork()
    {
        Thread.Sleep(100);
        lock (resourceB)
        {
            Thread.Sleep(100);
            lock (resourceA)
            {
                output += "T2#";
            }
        }
    }
}

Чтобы избежать блокировки таким образом, можно использовать Monitor.TryEnter (lock_object, timeout_in_milliseconds), чтобы проверить, не заблокирован ли замок на объекте. Если Monitor.TryEnter не удалось получить блокировку lock_object до timeout_in_milliseconds, он возвращает false, давая потоку возможность освободить другие удерживаемые ресурсы и уступить, тем самым предоставив другим потокам возможность завершить, как в этой слегка модифицированной версии выше :

private void button_Click(object sender, EventArgs e)
{
    MonitorWorkers workers = new MonitorWorkers();
    workers.StartThreads();
    textBox.Text = workers.GetResult();
}

private class MonitorWorkers
{
    Thread thread1, thread2;

    object resourceA = new object();
    object resourceB = new object();

    string output;

    public void StartThreads()
    {
        thread1 = new Thread(Thread1DoWork);
        thread2 = new Thread(Thread2DoWork);
        thread1.Start();
        thread2.Start();
    }

    public string GetResult()
    {
        thread1.Join();
        thread2.Join();
        return output;
    }

    public void Thread1DoWork()
    {
        bool mustDoWork = true;
        Thread.Sleep(100);
        while (mustDoWork)
        {
            lock (resourceA)
            {
                Thread.Sleep(100);
                if (Monitor.TryEnter(resourceB, 0))
                {
                    output += "T1#";
                    mustDoWork = false;
                    Monitor.Exit(resourceB);
                }
            }
            if (mustDoWork) Thread.Yield();
        }
    }

    public void Thread2DoWork()
    {
        Thread.Sleep(100);
        lock (resourceB)
        {
            Thread.Sleep(100);
            lock (resourceA)
            {
                output += "T2#";
            }
        }
    }
}

Обратите внимание, что это обходное решение полагается на то, что thread2 упрям ​​в отношении его блокировок и thread1, которые готовы дать, так что thread2 всегда имеет приоритет. Также обратите внимание, что thread1 должен повторить работу, которую он выполнил после блокировки ресурса A, когда он дает. Поэтому будьте осторожны при реализации этого подхода с более чем одним выходным потоком, так как тогда вы рискуете попасть в так называемый livelock - состояние, которое произойдет, если два потока продолжат делать первый бит их работы, а затем взаимно , начиная многократно.