В одном из обработчиков программа иногда вылетает, но не выдаёт ошибок. То есть, программа внезапно просто закрывается и всё Но это происходит не каждый раз. Если вручную пытаться вызывать это событие много раз - вылета нет. Сейчас добавил try-catch
и MessageBox
, чтобы попытаться отследить.
Но почему такое происходит? Должно же появляться окно с ошибкой. А тут ничего
Операционная система какая, тулчейн какой (язык программирования), какой режим сборки - для отладки или релиз…
Судя по тегу .Net, C#, Windows (хотя вполне может быть и Linux/Core/Native AOT и какой-нибудь F#)
Windows 11 Pro 21H2, Build 22000.978 Torrent Edition
а на втором компе: Windows 11 Pro 21H2, Build 22621.1413 Torrent Edition
C#, Net framework 4.7.2
Release
В дебаге, вызывая событие вручную много раз, не удаётся добиться вылета.
В Debug отладка обеспечивается фреймворком и отладчиком, в Release всего этого нет для увеличения скорости. Хочешь отлаживаться в релизе - логгируй самостоятельно. В windows есть программа Event Viewer, это официальный способ для просмотра логов от сервисов.
Логгирование (журналирование), по-древнерусски это “отладочная печать” называется.
Чтобы люди могли что-то сказать, надо привести код минимального примера где такое случается, я так думаю.
Но у меня не сервис
Ну ясен хрен
private void OnDumpingFinished(object sender, int errorCode)
{
if (InvokeRequired)
{
Invoke((MethodInvoker)delegate { OnDumpingFinished(sender, errorCode); });
}
else
{
try
{
StreamItem streamItem = (sender as ChannelChecker).StreamItem;
int id = FindStreamItemInListView(streamItem, listViewStreams);
if (id >= 0)
{
if (!_isClosing)
{
notifyIcon1.BalloonTipTitle = streamItem.ChannelName;
notifyIcon1.BalloonTipText = "Трансляция завершена!";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
notifyIcon1.ShowBalloonTip(5000);
}
//<<<<<<вылет где-то тут>>>>>>>>>
AddToLog(streamItem.ChannelName, errorCode == HlsDumper.DUMPING_ERROR_CANCELED ?
"Дампинг остановлен!" :
$"Плейлист потерян! Возможно, трансляция завершена! Код ошибки: {errorCode}");
ResetItem(streamItem);
listViewStreams.Items[id].SubItems[COLUMN_ID_STATUS].Text =
errorCode == HlsDumper.DUMPING_ERROR_CANCELED ? "Отменён" : "Завершён";
if (streamItem.Dumper.LostChunkCount > 0)
{
listViewStreams.Items[id].SubItems[COLUMN_ID_LOSTCHUNKS].Text =
streamItem.Dumper.LostChunkCount.ToString();
}
}
} catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private void ResetItem(StreamItem streamItem)
{
streamItem.DumpingFilePath = null;
streamItem.DumpingFileSize = -1L;
streamItem.DateServer = DateTime.MinValue;
streamItem.DateLocal = DateTime.MinValue;
streamItem.TimerRemaining = config.CheckingIntervalInactive;
int id = FindStreamItemInListView(streamItem, listViewStreams);
if (id >= 0)
{
listViewStreams.Items[id].SubItems[COLUMN_ID_TIMER].Text =
timerCheck.Enabled ? streamItem.TimerRemaining.ToString() : "Отключен!";
listViewStreams.Items[id].SubItems[COLUMN_ID_FILEPATH].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_FILESIZE].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_DELAY].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_CHUNKPROCESSINGTIME].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_CHUNKSIZE].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_NEWCHUNKS].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_PROCESSEDCHUNKS].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_FIRSTCHUNKID].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_LOSTCHUNKS].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_DUMPSTARTDATE].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_STATUS].Text = "Остановлено";
listViewStreams.Items[id].SubItems[COLUMN_ID_PLAYLISTERRORS].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_OTHERERRORS].Text = null;
listViewStreams.Items[id].SubItems[COLUMN_ID_PLAYLIST_URL].Text = null;
}
}
private void AddToLog(string channelName, string eventText)
{
string dateTime = DateTime.Now.ToString("yyyy.MM.dd, HH:mm:ss");
ListViewItem item = new ListViewItem(dateTime);
item.SubItems.Add(channelName);
item.SubItems.Add(eventText);
listViewLog.Items.Add(item);
if (MAX_LOG_COUNT > 1 && listViewLog.Items.Count > MAX_LOG_COUNT)
{
listViewLog.Items.RemoveAt(1);
}
listViewLog.EnsureVisible(listViewLog.Items.Count - 1);
}
Вроде ничего нигде не null
А в релизе оно ошибку не выдаёт, чтоли? Я писал скачивалку с ютуба и давал её юзать двум с половиной человекам. У них крашилось и там окошечко такое выскакивало, со стектрейсом. Я точно помню, как по этим стектрейсам дырки заделывал. И у меня у самого она много раз крашилась. Почему сейчас это окошечко не вылазит?
Сегодня ночью выдало NullPointerReference
. Значит, что-то где-то иногда бывает равно null
. Только я стектрейс забыл вывести Придётся опять ждать.
А пока у меня вопрос. У меня в коде примерно так сделано:
public delegate void XXXDelegate(object sender, MyClass a);
......
Task.Run(() =>
{
while (true)
{
if (flag)
{
xxx?.Invoke(this, a);
a = null;
break;
}
Thread.Sleep(2000);
}
}
на форме
private void OnXXX(object sender, a)
{
if (InvokeRequired)
{
Invoke((MethodInvoker)delegate { OnXXX(sender, a); });
}
else
{
Debug.WriteLine(a); // иногда NullPointerReference, предположительно из-за а
}
}
Строчка a = null;
выполнится сразу или будет ждать завершения обработчика?
А если без Control.Invoke
, а просто Invoke
у делегата?
Не знаю.
The common language runtime provides an
Invoke
method for each delegate type, with the same signature as the delegate. You do not have to call this method explicitly from C#, Visual Basic, or Visual C++, because the compilers call it automatically.
Delegate Class (System) | Microsoft Learn
Если рассуждать абстрактно, то делегат ничего об окнах не знает, значит не синхронизирует потоки. Но чтобы ответить точно, надо смотреть исходные тексты.
Почему это должен делать я, а не ты? Давай ты сначала сам посмотришь.
В общем, сами-по-себе делегаты ничего не перекидывают в другой поток.
Ну хотя-бы потому что ты профессиональный опытный программист (разве нет? во всяком случае, по твоим ответам видно, что это должно быть так), вероятно, с дипломом, а я жалкий кодер-выскочка. А это значит, что у тебя больше опыта в подобных вопросах и ты можешь грамотно и понятно изложить суть.
А если не знаешь ответа (или не уверен, или лень отвечать), то нужно так и написать - “я не знаю”. Если ты крутой кодер, зачем выказывать своё высокомерие по отношению к новичкам? Это просто глупость.
Да, ты прав. Мне не надо было ту строчку писать. Независимо от того, насколько я неопытный программист.
Конкретно такой пример как ты делаешь я никогда в жизни не делал (чтобы была форма и многопоточный обсчёт чего-то там). А в те времена, когда я это изучал, надо было сообщения windows в очередь вручную помещать, класса Control, отнаследованного от интерфейса ISynchonizeInvoke просто не было.
̶Н̶а̶д̶о̶ ̶м̶н̶е̶ ̶п̶о̶м̶е̶н̶ь̶ш̶е̶ ̶р̶е̶а̶г̶и̶р̶о̶в̶а̶т̶ь̶,̶ ̶м̶о̶ж̶е̶т̶ ̶д̶р̶у̶г̶и̶е̶ ̶л̶ю̶д̶и̶ ̶с̶ ̶б̶о̶л̶е̶е̶ ̶р̶е̶л̶е̶в̶а̶н̶т̶н̶ы̶м̶ ̶о̶п̶ы̶т̶о̶м̶ ̶т̶о̶г̶д̶а̶ ̶б̶у̶д̶у̶т̶ ̶о̶т̶в̶е̶ч̶а̶т̶ь̶.̶
Тёмные времена были. Чтобы просто включить компьютер, нужно было высшее образование.
Я не говорил, что ты/вы неопытный. Наоборот. Я говорю, что по вашим ответам складывается впечатление, что ты/вы знаете всё обо всём. А значит, ты/вы бывалый программист. Во всяком случае, мне с моими днищевскими знаниями так показалось. И тут я слышу: “почему я должен…?”
Простите… но зачем тогда сидеть на форуме, куда, в основном заходят только новички?