Подтвердить что ты не робот

Почему в С# первый вывод основного потока?

Я написал эту небольшую программу:

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 начинается сначала, а главное продолжается.

Есть ли объяснения для этого?

4b9b3361

Ответ 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 в одно и то же время (не все из них, но столько, сколько ваш компьютер может обрабатывать )