Итак, я попытался изучить, как использовать многопоточность, и заметил кое-что, чего не совсем понимаю.
В следующем фрагменте кода кажется, что 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()! Что здесь происходит? Каков процесс и его логика?
Не забывайте, что записи консоли «кэшируются».
@Selvin Почему?
@ J.vanLangen Что ты имеешь в виду под «кэшированным»?
Console.Out.Flush()потому что в другом случае у вас было бы «1 2 1 2 do», и если у вас есть «1 2 1 do 2», первый 1 исходит из foo, а не из потока ... конечно, он может работать по-разному так что оба результата возможны
Но блокирует ли «lock» запуск основного потока?
но у вас нет контроля над тем, что будет вызываться первым: foo из основного потока или foo из потока
@DanielReyhanian Это происходит, но только для foo(), поэтому, когда основной поток завершает работу foo(), второй поток входит и печатает «1» + ждет 3 секунды, в то время как основной поток может продолжить работу с doo() и в конце (после 3 секунд ) второй поток тоже завершает foo() и печатает «2».
с этим кодом на скрипке в основном у вас есть: 1m, 2m, 1t, do, 2t или 1m, 2m, do, 1t, 2t ... на ПК у меня также был 1t, 2t, 1m, 2m, do
с первым кодом у вас есть 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





Посмотрите, у вас здесь два потока, основной и второй поток (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()? Из-за сна?
Всегда в ОС у вас есть условия гонки, и каждый раз, когда вы работаете с потоком, вам нужно быть осторожным из-за этого! Вы не знаете, что поток ведьм сначала получит функцию или переменную. Возможно, основной поток в 10000 раз будет быстрее, но поток в 10001 раз получит функцию первым. Из-за этого вам нужно использовать семафор или монитор, чтобы попытаться выполнить синхронизацию.
нет... первые 1 и 2 из foo не thread