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

Нить не заканчивается при завершении основного потока

У меня есть странная проблема:

В моем приложении С# я создаю еще один поток, например:

Thread printThread = new Thread(printWorker);

printThread.Name = "Logger MainThread";
printThread.IsBackground = true;
printThread.Start();

Когда мой основной поток заканчивается, этот новый поток просто продолжает работать, хотя он помечен как Background.

Что может быть причиной этого? Этот объект держит объект Mutex, не уверен, что это может быть причиной...

Любые идеи кто-нибудь?

Здесь код из метода printWorker:

while (loggerIsActive)
{
    LogMessage log = LoggerQueue.Dequeue();

    if (log.message != null)
    {
        syncLogObj.WaitOne();
        lock (writerobj)
        {
            StreamWriter sw;

            if (!File.Exists(fName))
            {
                sw = File.CreateText(fName);
            }
            else
            {
                sw = new StreamWriter(fName, true);
            }

            using (sw)
            {
                if (log.message != "")
                {
                    if (log.message.EndsWith("\r\n"))
                    {
                        log.message =
                            log.message.Substring(0, log.message.Length - 2);
                    }

                    sw.WriteLine(string.Format("[{0}][{3}][{1}] | {2}",
                                               log.msgTime,
                                               log.level.ToString(),
                                               log.message,
                                               log.sender.ToString()));
                }

                sw.Flush();
                sw.Close();
            }
        }

        syncLogObj.ReleaseMutex();
    }

    Thread.Sleep(5);
}
4b9b3361

Ответ 1

Попробуйте следующее:

Запустите приложение через VS и выйдите из него. VS должен оставаться в режиме Debug, как вы описали. Нажмите кнопку Pause (Перерыв на все), а затем перейдите в Debug- > Windows- > Threads. Вы видите свой "Logger MainThread" в списке?

  • Если это так, дважды щелкните его, он должен привести вас к кодовой строке, которую в данный момент выполняет поток. Шаг-отладка оттуда и посмотреть, почему это не заканчивается.
  • Если вы не видите, чтобы он попытался найти другие потоки, которые не были прерваны и попытались найти проблему.

В противном случае с такими проблемами всегда полезно отслеживать состояние программы с помощью операторов System.Diagnostics.Debug.Print(вы можете видеть их печать в окне вывода VS).

Ответ 2

убейте его.

Не очень. Но это не телевидение. Читайте дальше:

1) Не уверен, что вы используете, используя его, но кажется, что вы должны блокировать loggerqueue перед очередью (main pgm) или dequeue (thread).
2) Не нужно блокировать writerobj только с этой настройкой. Но на самом деле вы должны так безопасно убить нить не во время записи:

  • Основная тема:
    • сделать все
    • перед закрытием:  -lock writerobj      -printthread.abort
  • рабочий поток:
    • добавить try catch для обработки исключения threadabort и просто выйти

Если вы правильно это сделаете, вам не придется использовать Waits и mutexes. Если вы все равно будете ждать, вам не понадобится спать.

Общие рекомендации для этого приложения: почему бы не войти в основной поток? если ваш журнал занят, результаты журнала будут бесполезны.

Но есть редкие случаи, когда это может быть неправильно. Entonces......

Общий совет, чтобы темы были хорошими для этой проблемы:

  • Основная программа
    • инкапсулировать ведение журнала (в частности, оставить флаг, очередь и рабочий поток ref) в объекте
    • 'глобальные снобы?' Регистрация является редким оправданием использования однотонной программы.
    • начать рабочий поток в объекте журнала с помощью метода
    • основной поток всегда вызывает единственный метод для объекта журнала для регистрации ошибки
    • Этот метод блокирует очередь и добавляет к ней.
    • Использовать Monitor/Pulse/Wait, sleep; полные примеры изобилуют; стоит изучить
      • потому что только этот поток попадает в файл в любом случае, если у вас нет нескольких процессов, вам не нужно waitone/releasemutex.
    • Этот метод ведения журнала отслеживает.объект
    • Это освобождает рабочий поток monitor.wait(это то, что простаивает процессор вместо сна)
    • заблокировать очередь, только внутри блокировки удалите объект в локальный ref; ничего.
    • Сделайте свой обычный код регистрации и цикл "exit check". Добавить
      • Ваш логический код может оставить сообщение незаписанным, если очередь заполнена при выходе:
      • перейдите в exit check, чтобы вы могли сделать это без дополнительной блокировки очереди:
        • перемещать объявление очереди в очереди; ничего не делать
        • изменить логику, пока на "loggerisactive" или "log!= null"
    • когда ваш основной поток заканчивается, в вашем коде выхода:
      • установить флаг закрытия
      • импульс объекта, который вы используете, чтобы ждать, пока он не обработает очередь.
      • Поток пройдет через.

Ответ 3

У вас много чего происходит, что вы явно не показываете...

Exmaple: у вас есть syncLogObj.WaitOne();, но мы не видим, где syncLogObj объявляется или используется в другом месте вашей программы.

Кроме того, вам это не нужно... избавиться от всего тэга syncLogObj (включая мусор "ReleaseMutex" )... у вас уже есть блокировка (blah) {}, и все, что вам нужно (из кода, который вы указали).

Вероятно, что основной поток НЕ заканчивается, вероятно, из-за этого или какого-либо другого объекта, который удерживает его открытым.

Итак, простые инструкции

  • Избавьтесь от syncLogObj (потому что у вас уже есть "блокировка" )
  • Убедитесь, что вы установили loggerIsActive = false где-то.

Изменить: Еще подробности!

Из того, что я вижу, вам вообще не нужен lock (writerobj), потому что (я уверен), у вас только есть один поток который записывает в журнал.

"Блокировка" существует только там, где есть два или более потока, которые запускают этот код (в основном).

Ответ 4

Если printworker не заканчивается до того, как ваш основной поток будет завершен, тогда главный умрет, и ваш поток printworker будет убит ОС. Если вы хотите, чтобы main дождался созданного вами потока, вы должны вызвать printThread.Join() в главном. Это заставит вас ждать вашего потока.

Когда основная часть заканчивается, ваша программа умирает, и ваш printThread будет уничтожен ОС, он не будет работать.

Из здесь

Фоновые потоки идентичны передние потоки с одним исключением: фоновый поток не поддерживает управляемая среда исполнения. Как только все передние потоки были остановлен в управляемом процессе (где файл .exe является управляемой сборкой), система останавливает весь фон потоков и отключается.

Ответ 5

Tony the Tiger имеет правильную идею, но нужно добавить дополнительный код, чтобы убить поток до закрытия приложения.

printThread.Join(1000);
if(printThread!=null && printThread.IsAlive)
    printThread.Abort();

Ответ 6

Thread.Abort();
Thread.Dispose();

Это должно сделать это, если я не ошибаюсь.