Есть служба в ней работает порядка 20 потоков порожденных new Thread.
В потоке работает такой код
while (true)
{
doSmth();//запросы к БД
Thread.Sleep(5000);
}
Внезапно исчезает один поток (не отображается в логах).
Пока предположение, что у потока упал приоритет (винда понизила?) и теперь у него нет шансов получить время для работы.
Возможно ли такое?
Здравствуйте, Qt-Coder, Вы писали:
QC>Внезапно исчезает один поток (не отображается в логах). QC>Пока предположение, что у потока упал приоритет (винда понизила?) и теперь у него нет шансов получить время для работы. QC>Возможно ли такое?
Нет. Он может быть неактивен, но это не причина для его смерти.
Поток может исчезнуть по одной из 2 причин
1. Сам закончился. В том числе вследствие возникшего в нем и перехваченного исключения.
2. Кто-то ему TerminateThread сделал.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Поток может исчезнуть по одной из 2 причин
PD>1. Сам закончился. В том числе вследствие возникшего в нем и перехваченного исключения. PD>2. Кто-то ему TerminateThread сделал.
QC>Внезапно исчезает один поток (не отображается в логах).
А он точно не висит в каком-то месте?
Если возможно, то следует исследовать живой процесс или дамп памяти через Debug Diagnostic Tool (DebugDiag) или WinDbg.
Здравствуйте, m2user, Вы писали:
M>Если возможно, то следует исследовать живой процесс или дамп памяти через Debug Diagnostic Tool (DebugDiag) или WinDbg.
Или через Process Explorer. (<Select Process> — Properties — Threads)
Здравствуйте, m2user, Вы писали:
QC>>Внезапно исчезает один поток (не отображается в логах).
M>А он точно не висит в каком-то месте? M>Если возможно, то следует исследовать живой процесс или дамп памяти через Debug Diagnostic Tool (DebugDiag) или WinDbg.
Он точно не вышел из цикла while (true), т.к. после выхода стоит логгирование. Где-то заблудился в коде, наверное, надо искать, может на запросе к БД завис, хотя там стоят таймауты. Завис наглухо, обнаружили только через 5 суток.
Отладить нельзя, просто перезапустили службу.
Здравствуйте, Qt-Coder, Вы писали:
QC>Он точно не вышел из цикла while (true), т.к. после выхода стоит логгирование. Где-то заблудился в коде, наверное, надо искать, может на запросе к БД завис, хотя там стоят таймауты. Завис наглухо, обнаружили только через 5 суток. QC>Отладить нельзя, просто перезапустили службу.
Если еще раз произойдет, запусти Process Explorer и посмотри у этого потока Stack. Может, что-то удастся понять.
PD>1. Сам закончился. В том числе вследствие возникшего в нем и перехваченного исключения.
Внутри потока случилось исключение и его не обработали. Но автор говорит есть обработчик с логгированием. Тогда возможно:
1a. StackOverflowException — проскочит мимо обработчика. Вот только не уверен не убьет ли он потом весь процесс. Вроде нет?
1b. OutOfMemoryException — залетит в обработчик, но при попытке залоггировать опять памяти может не хватить.
Если Windows можно попытаться какие-то концы в Eventlog поискать.
M>>Если возможно, то следует исследовать живой процесс или дамп памяти через Debug Diagnostic Tool (DebugDiag) или WinDbg.
PD>Или через Process Explorer. (<Select Process> — Properties — Threads)
Дамп можно и через PE снять (при этом очень желательно чтобы разрядность (32/64) процесса PE совпадала с разрядностью проблемного процесса).
А вот всесторонне исследовать дамп лучше уже через специализированный инструмент.
Там же можно и managed/unmanaged стек посмотреть, и состояние переменных. И живой процесс уже не нужен (можно перезапускать).
Здравствуйте, m2user, Вы писали:
M>Дамп можно и через PE снять (при этом очень желательно чтобы разрядность (32/64) процесса PE совпадала с разрядностью проблемного процесса).
Насколько я понимаю, об этом он сам заботится. При запуске procexp запускается еще и procexp64, а там они уже как-то сами разбираются, каким процессом кому заниматься.
M>>Дамп можно и через PE снять (при этом очень желательно чтобы разрядность (32/64) процесса PE совпадала с разрядностью проблемного процесса). PD>Насколько я понимаю, об этом он сам заботится. При запуске procexp запускается еще и procexp64, а там они уже как-то сами разбираются, каким процессом кому заниматься.
Да, скорее всего Вы правы. Я с Windows Task Manager попутал, он ведь тоже умеет снимать дампы.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Насколько я понимаю, об этом он сам заботится. При запуске procexp запускается еще и procexp64, а там они уже как-то сами разбираются, каким процессом кому заниматься.
Здравствуйте, syrompe, Вы писали:
PD>>1. Сам закончился. В том числе вследствие возникшего в нем и перехваченного исключения.
S>Внутри потока случилось исключение и его не обработали. Но автор говорит есть обработчик с логгированием. Тогда возможно:
Необработанное обрушило бы весь процесс, а не один поток, остальные потоки весело булькают.
Здравствуйте, Qt-Coder, Вы писали:
QC>Необработанное обрушило бы весь процесс, а не один поток, остальные потоки весело булькают.
Если процесс является службой (например ASP.NET), то он от этого не упадёт. У вас же процесс не завершается, если например в рамках обработки запроса в одном из потоков произошло необработанное исключение.
Вот если в консольном приложении такое сделать, то да, процесс будет завершён.
4>Если процесс является службой (например ASP.NET), то он от этого не упадёт. У вас же процесс не завершается, если например в рамках обработки запроса в одном из потоков произошло необработанное исключение. 4>Вот если в консольном приложении такое сделать, то да, процесс будет завершён.
Вроде ТС говорит про Windows Service, а не про ASP.NET web service.
Здравствуйте, m2user, Вы писали:
4>>Если процесс является службой (например ASP.NET), то он от этого не упадёт. У вас же процесс не завершается, если например в рамках обработки запроса в одном из потоков произошло необработанное исключение. 4>>Вот если в консольном приложении такое сделать, то да, процесс будет завершён.
M>Вроде ТС говорит про Windows Service, а не про ASP.NET web service.
Так и есть.
M>>Вроде ТС говорит про Windows Service, а не про ASP.NET web service. 4>ASP.NET приведён в качестве примера, т.к. Windows Service это тоже служба, и логика обработки потоков у них идентичная.
Я не сильно разбираюсь в том, как работает ASP.NET.
Но что касается Windows Service, то от обычного консольного приложения он по сути отличается только обработкой RPC запросов от Service Control Manager и регистрацией в реестре.
И от неперехваченных исключений падает точно также, как любое консольное приложение.
Полагаю, что ТС это может проверить несложным практическим экспериментом.
Здравствуйте, m2user, Вы писали:
M>>>Вроде ТС говорит про Windows Service, а не про ASP.NET web service. 4>>ASP.NET приведён в качестве примера, т.к. Windows Service это тоже служба, и логика обработки потоков у них идентичная.
M>Я не сильно разбираюсь в том, как работает ASP.NET. M>Но что касается Windows Service, то от обычного консольного приложения он по сути отличается только обработкой RPC запросов от Service Control Manager и регистрацией в реестре. M>И от неперехваченных исключений падает точно также, как любое консольное приложение.
M>Полагаю, что ТС это может проверить несложным практическим экспериментом.
У меня было необработанное исключение в потоке, который создался в методе OnStart() сервиса через new Thread(() => {...}).Start(), а именно ParseException. Так вот это было тихо проглочено, чем вызвало 3 часа головной боли в дебагере.
Полагаю, что вы можете убедиться в этом с помощью несложного практического эксперимента.
D>Полагаю, что вы можете убедиться в этом с помощью несложного практического эксперимента.
Application: WindowsService1.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Web.Query.Dynamic.ParseException
at WindowsService1.Service1.Run()
at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()
код
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace WindowsService1 {
public partial class Service1 : ServiceBase {
public Service1() {
InitializeComponent();
}
protected override void OnStart(string[] args) {
new Thread(Run).Start();
}
protected override void OnStop() {
}
void Run() {
throw new System.Web.Query.Dynamic.ParseException("", 0);
}
}
}
Здравствуйте, m2user, Вы писали:
M>Но что касается Windows Service, то от обычного консольного приложения он по сути отличается только обработкой RPC запросов от Service Control Manager и регистрацией в реестре. M>И от неперехваченных исключений падает точно также, как любое консольное приложение.
Да, действительно это так. Занятно, что в FW 1.0/1.1 исключение выброшенное не из главного потока не приводило к завершению процесса.
In the .NET Framework versions 1.0 and 1.1, an unhandled exception that occurs in a thread other than the main application thread is caught by the runtime and therefore does not cause the application to terminate. Thus, it is possible for the UnhandledException event to be raised without the application terminating. Starting with the .NET Framework version 2.0, this backstop for unhandled exceptions in child threads was removed, because the cumulative effect of such silent failures included performance degradation, corrupted data, and lockups, all of which were difficult to debug.
QC>Похоже причина в этом QC> GC.Collect(2, GCCollectionMode.Forced); QC> GC.WaitForPendingFinalizers();
Ну да, WaitForPendingFinalizers может висеть неопределенное время в зависимости от того, что застряло в очереди на финализацию.
Если ты повторил проблему и снял дамп, то через WinDbg можно посмотреть, что висит в finalizer queue.
Вообще в норме не следует вызывать GC.Collect и GC.WaitForPendingFinalizers вручную. Присутствие их в коде уже повод насторожиться.
Здравствуйте, m2user, Вы писали:
QC>>Похоже причина в этом QC>> GC.Collect(2, GCCollectionMode.Forced); QC>> GC.WaitForPendingFinalizers();
M>Ну да, WaitForPendingFinalizers может висеть неопределенное время в зависимости от того, что застряло в очереди на финализацию. M>Если ты повторил проблему и снял дамп, то через WinDbg можно посмотреть, что висит в finalizer queue.
M>Вообще в норме не следует вызывать GC.Collect и GC.WaitForPendingFinalizers вручную. Присутствие их в коде уже повод насторожиться.
Нет, не снял, просто больше не вижу что могло зависнуть.
QC>Нет, не снял, просто больше не вижу что могло зависнуть.
Если предполагаешь, что именно в этом дело, то можно просто и без воспроизведения снять дамп и посмотреть, сколько объектов в finalizer queue. В идеале их должно быть относительно мало (объекты у которых ты не имеешь возможности явно вызвать Dispose — например Thread и т.п.).
Ну и добавить трассировку времени выполнения GC.Collect и GC.WaitForPendingFinalizers.