Как работает Thread.Sleep()?

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

В следующем фрагменте кода кажется, что 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()! Что здесь происходит? Каков процесс и его логика?

нет... первые 1 и 2 из foo не thread

Selvin 02.02.2019 23:54

Не забывайте, что записи консоли «кэшируются».

Jeroen van Langen 02.02.2019 23:55

@Selvin Почему?

Daniel Reyhanian 02.02.2019 23:56

@ J.vanLangen Что ты имеешь в виду под «кэшированным»?

Daniel Reyhanian 02.02.2019 23:56
Console.Out.Flush()
Jeroen van Langen 02.02.2019 23:57

потому что в другом случае у вас было бы «1 2 1 2 do», и если у вас есть «1 2 1 do 2», первый 1 исходит из foo, а не из потока ... конечно, он может работать по-разному так что оба результата возможны

Selvin 02.02.2019 23:59

Но блокирует ли «lock» запуск основного потока?

Daniel Reyhanian 03.02.2019 00:06

но у вас нет контроля над тем, что будет вызываться первым: foo из основного потока или foo из потока

Selvin 03.02.2019 00:07

@DanielReyhanian Это происходит, но только для foo(), поэтому, когда основной поток завершает работу foo(), второй поток входит и печатает «1» + ждет 3 секунды, в то время как основной поток может продолжить работу с doo() и в конце (после 3 секунд ) второй поток тоже завершает foo() и печатает «2».

Ondřej Kubíček 03.02.2019 00:08

с этим кодом на скрипке в основном у вас есть: 1m, 2m, 1t, do, 2t или 1m, 2m, do, 1t, 2t ... на ПК у меня также был 1t, 2t, 1m, 2m, do

Selvin 03.02.2019 01:01

с первым кодом у вас есть 6 вариантов 1m, 1t , 2m, 2t, do, 1m, 1t , 2m, do, 2t, 1m, 1t, 2t, 2m, do, 1t, 1m , 2t, 2m, do, 1t, 1m , 2m, do, 2t, 1t, 1m, 2m, 2t, do

Selvin 03.02.2019 01:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
322
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

Почему основной поток выполняется перед потоком foo()? Из-за сна?

Daniel Reyhanian 03.02.2019 00:43

Всегда в ОС у вас есть условия гонки, и каждый раз, когда вы работаете с потоком, вам нужно быть осторожным из-за этого! Вы не знаете, что поток ведьм сначала получит функцию или переменную. Возможно, основной поток в 10000 раз будет быстрее, но поток в 10001 раз получит функцию первым. Из-за этого вам нужно использовать семафор или монитор, чтобы попытаться выполнить синхронизацию.

Милош Вељковић 03.02.2019 00:54

Другие вопросы по теме