Дедлок в WinForms, который предотвращается нажатием правой кнопки мыши на панели задач
Я столкнулся со странной проблемой с нашим приложением Windows C # / .NET. На самом деле это приложение с графическим интерфейсом, моя работа - это сетевой компонент, включенный в сборку.Я не знаю код основного приложения / приложения с графическим интерфейсомЯ мог связаться с нимРазработчик, хотя.
Теперь приложениеУ пользовательского интерфейса есть кнопки для "Начните" а также "Стоп" сетевой движок. Обе кнопки работают. Чтобы сделать мой компонент безопасным для потоков, я использую блокировку вокруг трех методов. Я не'Я не хочу, чтобы клиент мог вызывать Stop () до завершения Start (). Кроме того, есть таймер опроса.
Я попытался показать вам как можно меньше строк и упростил задачу:
private Timer actionTimer = new Timer(new
TimerCallback(actionTimer_TimerCallback),
null, Timeout.Infinite, Timeout.Infinite);
public void Start()
{
lock (driverLock)
{
active = true;
// Trigger the first timer event in 500ms
actionTimer.Change(500, Timeout.Infinite);
}
}
private void actionTimer_TimerCallback(object state)
{
lock (driverLock)
{
if (!active) return;
log.Debug("Before event");
StatusEvent(this, new StatusEventArgs()); // it hangs here
log.Debug("After event");
// Now restart timer
actionTimer.Change(500, Timeout.Infinite);
}
}
public void Stop()
{
lock (driverLock)
{
active = false;
}
}
Вот как воспроизвести мою проблему. Как я уже сказал, обе кнопки Start и Stop работают, но если вы нажмете Start (), иво время выполнения TimerCallback нажмите Stop ()это предотвращает возврат TimerCallback. Он висит точно в той же позиции, StatusEvent. Таким образом, блокировка никогда не снимается и графический интерфейс также зависает, потому чтоВызов метода Stop () не может быть продолжен.
Теперь я заметил следующее: если приложение зависает из-за этоготупиковой» и я щелкаю приложение на панели задач правой кнопкой мыши, оно продолжается. Это просто работает, как и ожидалось. У кого-нибудь есть объяснение или лучшее решение для этого?
Кстати, я также попробовал это с InvokeIfRequired, так как я неНе знаю, как работает приложение GUI. Это необходимо, если мой StatusEvent что-то изменит в GUI. Поскольку у меня нет ссылок на элементы управления GUI, я использовал (предполагая только одну цель):
Delegate firstTarget = StatusEvent.GetInocationList()[0];
ISynchronizeInvoke syncInvoke = firstTarget.Target as ISynchronizeInvoke;
if (syncInvoke.InvokeRequired)
{
syncInvoke.Invoke(firstTarget, new object[] { this, new StatusEventArgs() });
}
else
{
firstTarget.Method.Invoke(firstTarget.Target, new object[] { this, new StatusEventArgs() });
}
Этот подход неизменить проблему. Я думаю, это потому, что я вызываю основное приложение.обработчики событий, а не на элементах управления GUI. То есть основное приложение отвечает за Invoking? Но в любом случае AFAIK, не использующий Invoke, хотя и необходимый, не приведет к тупику, подобному этому, но (надеюсь) к исключению.