Как работает Thread.Sleep ()? - PullRequest
0 голосов
/ 03 февраля 2019

Итак, я попытался изучить, как использовать многопоточность, и заметил кое-что, чего не совсем понимаю.

В следующем фрагменте кода похоже, что doo () запускается до того, какпоток завершен, хотя foo совпадает с потоком:

static void Main(string[] args)
{
    new Thread(new ThreadStart(foo)).Start();
    foo();
    doo();
}

public static void foo()
{

    Console.WriteLine("1");
    Thread.Sleep(3000);
    Console.WriteLine("2");
}

public static void doo()
{
    Console.WriteLine("do");
}

Вывод:

1 // Thread

1 // foo

2 // foo

do // doo

2 // Thread

Предполагая, что doo () не может запускаться без foo() сделано, мы предполагаем, что последний вывод «2» пришел из первого потока.

Как это возможно?Хотя функции foo () и Thread имеют одинаковое время ожидания, поскольку они являются одинаковыми функциями, почему получается, что Thread (который выполняется первым) завершает в последнюю очередь?

Оператор блокировки

Теперь, если мы добавим оператор блокировки, например:

static object syncLock = new object();

static void Main(string[] args)
{
    new Thread(new ThreadStart(foo)).Start();
    foo();
    doo();
}

public static void foo()
{
    lock (syncLock)
    {
        Console.WriteLine("1");
        Thread.Sleep(3000);
        Console.WriteLine("2");
    }        
}

public static void doo()
{
    Console.WriteLine("do");
}

Вывод:

1 // Thread

2 // Thread

1 // foo

do // doo

2 // Thread

Теперь кажется, что doo () запускается до того, как foo () заканчивается!Что здесь происходит?Каков процесс и логика, стоящая за ним?

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Посмотрите, у вас здесь фактически два потока: основной и второй (foo ()). После new Thread (new ThreadStart (foo)). Start (); выполнение начнется сосновной поток, что означает, что этот поток (основной поток) будет пытаться вызвать foo (), то есть ваше «1», после этого основной поток перейдет в спящий режим, а второй поток помечается звездой foo (), то есть «один-второй» «1», и sec перейти в спящий режим. Теперь основной поток проснется и завершит работу «2», «do», а последний «2» будет из потока sec.То есть без блокировки.

С блокировкой основной поток выполнит foo (), а секунда будет заблокирована («1», 3sec, «2»), когда foo () разблокирует, что означает, secПоток может вызвать foo (), и когда это произойдет, sec print «1» ad перейдет в спящий режим, и теперь (пока sec находится в спящем режиме, CPU ищет поток, который может быть выполнен), поэтому CPU исполняет основной поток и печатает «do»а затем sec проснется и напечатает "2" ..

0 голосов
/ 03 февраля 2019

Как сказано в комментариях, записи консоли кэшируются.

Я просто добавил массив и затем напечатал его значения в конце.

class Program
    {
        static object syncLock = new object();
        static int[] arr = new int[5];
        static int counter = 0;
        static void Main(string[] args)
        {
            new Thread(new ThreadStart(foo)).Start();
            foo();
            doo();
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(arr[i]);
            }
        }

        public static void foo()
        {
            arr[counter] = 1;
                counter++;
                Thread.Sleep(3000);
            arr[counter] = 2;
            counter++;
        }

        public static void doo()
        {
            arr[counter] = 3;
            counter++;
        }

    }

Вывод:

1

1

2

2

3

Теперь это делает намного большесмысл.Спасибо!Любая другая информация о нитях, снах и замках приветствуется.

...