Почему в С# первый вывод основного потока?
Я написал эту небольшую программу:
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(WriteX);
t.Start();
for (int i = 0; i < 1000; i++)
{
Console.Write("O");
}
}
private static void WriteX()
{
for (int i = 0; i < 1000; i++)
{
Console.Write(".");
}
}
}
Я запускал его примерно пятьдесят раз, и первый символ на консоли всегда был "O". Это странно для меня, потому что поток t
начинается сначала, а главное продолжается.
Есть ли объяснения для этого?
Ответы
Ответ 1
Вероятно, это связано с тем, что Thread.Start сначала вызывает изменение состояния потока, на котором он вызывается, и ОС планирует его выполнить, тогда как основной поток уже запущен и не нуждается в этих двух шагах, Вероятно, это причина, по которой оператор в основном потоке выполняет первую, а во вновь созданном потоке. Имейте в виду, что последовательность выполнения потоков не гарантируется.
Thread.Start Method
1) Метод Thread.Start Приводит операционную систему к изменению состояния текущий экземпляр в ThreadState.Running.
2) Как только поток находится в состоянии ThreadState.Running, система может запланировать его выполнение. Поток начинается с первая строка метода, представленная ThreadStart
Изменить. Мне кажется, что представление этого в графической форме сделает это более понятным и понятным. Я попытался показать последовательность выполнения потока на диаграмме ниже.
![enter image description here]()
Ответ 2
Вы говорите:
"Это странно для меня, потому что поток t начинается сначала, а главное продолжается".
Это неверно. "Основной" протектор уже запущен. Когда t.Start();
выполняется, OS сообщается, что t
находится в рабочем состоянии. Затем ОС заплатит время выполнения для потока "скоро". Это что-то другое, кроме того, что ОС инструктировано прекратить выполнение этого потока до тех пор, пока не начнется поток t
. Другими словами, когда возвращается Start
, нет гарантии, что поток уже начал выполнение.
Ответ 3
Больше советов, чем не ответа:
(Обратите внимание, что я не вижу реального использования для того, чего вы пытаетесь достичь, поэтому я рассматриваю вашу проблему как мысленный эксперимент/доказательство концепции, которая не объясняется подробно.)
Если вы хотите, чтобы ваши потоки были "расы" для контроля, не давайте основной теме начать игру! Создание потока имеет некоторые накладные расходы, и основной поток уже создан (поскольку он создает другой поток). Если вы ищете в основном равные шансы как для основного, так и для рабочего потока, вам следует подождать, пока ваш рабочий поток будет создан в основном потоке и дождитесь, когда основной поток начнет гонку в фоновом потоке. Это может быть достигнуто с помощью объектов синхронизации.
На практике это будет выглядеть так:
Вы должны объявить два элемента ManualResetEvents, которые видны как для основного, так и для фонового потока следующим образом:
private static ManualResetEvent backgroundThreadReady = new ManualResetEvent(false);
private static ManualResetEvent startThreadRace = new ManualResetEvent(false);
Затем в основном потоке вы должны дождаться инициализации потока:
static void Main(string[] args)
{
Thread t = new Thread(WriteX);
t.Start();
backgroundThreadReady.WaitOne(); // wait for background thread to be ready
startThreadRace.Set(); // signal your background thread to start the race
for (int i = 0; i < 1000; i++)
{
Console.Write("O");
}
}
И в вашей теме:
private static void WriteX()
{
backgroundThreadReady.Set(); // inform your main thread that this thread is ready for the race
startThreadRace.WaitOne(); // wait 'till the main thread starts the race
for (int i = 0; i < 1000; i++)
{
Console.Write(".");
}
}
Обратите внимание, что я мог использовать другие ожидающие объекты синхронизации (mutex, событие автосохранения, даже блокировку критического раздела с некоторыми хаками, я просто выбираю самое простое и быстрое решение, которое можно легко расширить).
Ответ 4
В основном требуется время для запуска потока вверх. Вы выполняете код потока одновременно с остальной частью первого метода. Поэтому, принимая во внимание время, необходимое для запуска потока, а затем дойти до точки, где он пишет ".". это имеет смысл?
Если у вас есть своего рода reset кнопка в вашем приложении, чтобы начать все снова (без выхода), вы можете обнаружить, что первым символом является ".". потому что поток уже существует.
Ответ 5
Ваш код не является детерминированным. Ваш код не содержит примитивов потоков, которые планируют приоритет одного потока над другим или для одного потока ждать другого.
Ответ 6
Основной процесс продолжит выполнение следующих инструкций после вызова потока. Потребуется время, чтобы начать процесс потока как легкий процесс.
Ответ 7
Есть только одна причина, по которой основной поток будет завершен до созданного потока, и это потому, что для начала потока требуется время. Единственный раз, когда вы будете использовать потоки для ускорения работы программы, - это то, когда 2 задачи могут выполняться в одно и то же время. Если вы хотите сделать второй цикл первым, взгляните на Parallel.For петли в С#... они будут запускать каждый цикл в цикле for в одно и то же время (не все из них, но столько, сколько ваш компьютер может обрабатывать )