Монитор.PulaseAll выдает ошибку

#c#

#c#

Вопрос:

Что не так с этим примером, он выдает ошибку «Метод синхронизации объекта был вызван из несинхронизированного блока кода» на мониторе.PulaseAll(гггг)?

 class Program
{
    static object yyy = 1;

    public static void test(int x)
    {

        while (true)
        {
            lock (yyy)
            {
                Console.WriteLine("T"   x.ToString());
                while (x != (int)yyy)
                {
                    Monitor.Wait(yyy);
                    continue;
                }

                Console.Write(new string(x.ToString()[0], 20));

                yyy = 1   (int)yyy;
                yyy = ((int)yyy == 4) ? 1 : yyy;

                Console.WriteLine("------------------------1--");
                Monitor.PulseAll(yyy);
                Console.WriteLine("------------------------2--");
            }
        }
    }

    public static void Main ()
    {
        Thread t1 = new Thread(new ThreadStart(() => { test(3);}));
        Thread t2 = new Thread(new ThreadStart(() => { test(2);}));
        Thread t3 = new Thread(new ThreadStart(() => { test(1);}));

        t1.Start();
        t2.Start();
        t3.Start();

        while (true)
            Thread.Sleep(500);
    }
}
  

Ответ №1:

Ошибка здесь заключается в изменении объекта блокировки.

Чтобы запустить [все], у вас должна быть блокировка. Похоже, что у вас есть блокировка, но если вы внимательно посмотрите, вы переназначаете yyy в коде, так что это другой объект.

По этой причине объектами блокировки обычно являются readonly поля.

Кроме того, блокировка типа значения в штучной упаковке или строки, как правило, является плохой идеей; наиболее подходящим объектом блокировки является:

 private readonly object syncLock = new object();
  

(может быть дополнительно static при необходимости)

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