Threading в Form_Load - приложение теперь зависает внезапно - PullRequest
1 голос
/ 23 февраля 2012

Извините за длинный пост, я просто хочу проиллюстрировать мою ситуацию как можно лучше. Прочитайте элементы, выделенные полужирным шрифтом, и проверьте код, если вы хотите быстро понять суть проблемы.

Я использую ClickOnce для развертывания приложения на C # и предпочел, чтобы мое приложение проверяло наличие обновленийвручную, используя ApplicationDeployment Class вместо того, чтобы позволять ему выполнять проверку обновлений для меня.

Программа представляет собой специализированный сетевой сканер, который выполняет поиск сетевых устройств, созданных компанией, в которой я работаю.Как только главное окно загружено, отображается запрос, спрашивающий, хочет ли пользователь сканировать сеть.Если они говорят «Да», начинается сканирование, которое может занять минуту или две, в зависимости от настроек сети;в противном случае он просто ждет, когда пользователь выполнит какое-либо действие.

Одна из последних вещей, которые я делаю в Form_Load, - это создание нового потока, который проверяет наличие обновлений.Все это работало нормально в течение нескольких месяцев, примерно через 12 выпусков, и внезапно перестало работать.Я вообще не изменил код обновления и не изменил последовательность действий при запуске приложения.

Смотря на код, я думаю, что вижу, почему он работает неправильно и хотелчтобы подтвердить, что то, что я считаю правильным.Если это так, то возникает вопрос о том, почему он работал раньше - но я тоже не слишком обеспокоен этим.

Рассмотрим следующий код:

frmMain.cs

private void Form1_Load(object sender, EventArgs e)
{
    // set up ui, load settings etc

    Thread t = new Thread(new ParameterizedThreadStart(StartUpdateThread));
    t.Start(this);
}

private void StartUpdateThread(object param)
{
    IWin32Window owner = param as IWin32Window;

    frmAppUpdater.CheckForUpdate(owner);
}

frmAppUpdater.cs

public static void CheckForUpdate(IWin32Window owner)
{
    if (ApplicationDeployment.IsNetworkDeployed) {
        Console.WriteLine("Going to check for application updates.");
        parentWindow = owner;

        ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
        ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
        ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);

        ad.CheckForUpdateAsync();
        // CAN/WILL THE THREAD CREATED IN FORM1_LOAD BE TERMINATED HERE???
    }
}

Когда обратный вызов CheckForUpdateAsync() завершается, если обновление недоступно, вызов метода просто возвращается;если доступно обновление, я использую цикл для блокировки до тех пор, пока не произойдут 2 события: пользователь отклонил «Вы хотите сканировать приглашение» И в настоящее время сканирование не выполняется.

Цикл выглядит так, чтопроисходит в ad_CheckForUpdateCompleted:

while (AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) {
    System.Threading.Thread.Sleep(5000);
}

Я сплю 5 секунд, потому что я подумал, что это происходит в отдельном потоке, и, кажется, какое-то время он работал хорошо.

Мой главный вопрос по поводу приведенного выше кода:
Когда из CheckForUpdate вызывается ad.CheckForUpdateAsync();, завершается ли поток, созданный в Form1_Load (или он может прерваться)?Я подозреваю, что это возможно, потому что последующий асинхронный вызов заставляет метод возвращаться, а затем запускать другой поток?

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

Я был бы рад выложить полный код для frmAppUpdater.cs, если это будет полезно.

Ответы [ 2 ]

1 голос
/ 23 февраля 2012

Смотрите это сообщение на Асинхронные делегаты против темы / ThreadPool?

кажется, что ваш метод загрузки формы выполняет синхронную работу. Вы упоминаете, что используете развертывание clickonce. Изменилось ли двоичное расположение после предыдущего выпуска или изменились разрешения для этого ресурса. Похоже, работа (checkupdates) в теме никогда не заканчивается и никогда не возвращается в форму.

в качестве немедленного исправления я бы изменил подход Thread для делегирования - если вы используете делегат, тогда это становится меньше проблемой клиента (форма будет отвечать конечному пользователю), но основная проблема остается.

в качестве следующего шага, я бы прошел http://msdn.microsoft.com/en-us/library/ms229001.aspx и сделал бы поиск неисправностей

1 голос
/ 23 февраля 2012

Когда ad.CheckForUpdateAsync(); вызывается из CheckForUpdate, поток, созданный в Form1_Load, завершается (или может прекратить работу)?

Если вызов CheckForUpdateAsync() является асинхронным, тогда да, поток будет прерван, иначе он не будет.

Если вы подозреваете, что Sleep вызвал зависание приложения, тогда эти две переменные AppGlobals.ScanInProgress и AppGlobals.ScanPromptVisible, вероятно, всегда установлены на true! Вы должны начать смотреть на код, который устанавливает их на true и посмотреть, что там происходит.

Чтобы избежать зависания приложения, вы можете ввести переменную, чтобы избежать бессонницы:

int nTrials = 0;
while ((AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) && (nTrials < 5)) {
    System.Threading.Thread.Sleep(5000);
    nTrials++;
}
// Check the results and act accordingly

Лично мне не нравится использовать Sleep для синхронизации потоков. .NET предлагает набор классов , которые идеально подходят для синхронизации потоков, WaitHandle является одним из них.

...