Ошибка, возникающая во время теста синхронизации потока. Задача не может заблокировать поток от запуска следующего кода - PullRequest
0 голосов
/ 16 февраля 2020

Вопросы заключаются в следующем: Согласно MSDN, когда поток получает блокировку, Monitor.Enter блокирует другие потоки, пока поток не снимет блокировку. Однако во время теста Monitor.Enter (объект) может блокировать выполнение другими потоками следующего блока кода в случае Thread, и он все еще выполняет следующий блок кода без блокировки в случае Task.

class program
{
    static void Main(string[] ars)
    {
        for(int i = 0; i <5; i++)
        {
            new Thread(Func){ IsBackground = true}.Start();
        }
        Console.ReadKey();

        //for(int i = 0;i< 5;i++)
        //{
        //  Task.Factory.StartNew(Func);
        //}
        Console.ReadKey();
    }

    static void Func()
    {
        Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}");
    bool b = false;
    Monitor.Enter(locker, ref b);
    Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} 执行 b = {b}");
    }
}

Результат: Задача:

图片说明

Тема:

图片说明

Результат: Как показано на рисунке выше, Задача выполняет Monitor.Enter (locker) и выполняет следующий код дважды, в то время как Thread выполняет его только один раз.

Причина: лично вы подозреваете, что тот же поток может продолжать работать без снятия блокировки? Надеюсь ответ

1 Ответ

1 голос
/ 16 февраля 2020

Блокировки монитора могут быть введены одним и тем же потоком несколько раз несколько раз и разблокируют его, когда будет выполнено одинаковое количество выпусков. Это называется повторным входом.

   private void MonitorSameThreadTest() {
    var obj = new object();

    lock (obj) {
        // Lock obtained. Must exit once to release.
        // No *other* thread can obtain a lock on obj
        // until this (outermost) "lock" completes.
        lock (obj) {
            // Same thread can actually enter again
            var lockTaken = false;
            try {
                Monitor.Enter(obj, ref lockTaken);
                // Same thread can actually enter again
                // We've *re-entered* lock again.
            }
            finally {
                if (lockTaken) Monitor.Exit(obj);

                // Must exit twice to release.
            }
        }
        // Must exit once to release.
    }
    // the lock allowing other threads to obtain it.
}
...