Здравствуйте, AlexNek, Вы писали:
AN>Как бороться?
ProgressWorker.Run — асинхронный метод. Он вызывается параллельно с основным потоком.
В данном коде подразумевается, что будет выполнена реструктуризация, а затем основной поток продолжит выполнение. А на самом деле поток реструктуризации и основной поток работают одновременно. Кто-кого из этих потоков обгонит — не известно.
Здравствуйте, Буравчик, Вы писали:
Б> AN>Как бороться?
Б> ProgressWorker.Run — асинхронный метод. Он вызывается параллельно с основным потоком.
Я так тоже думал.
Б> В данном коде подразумевается, что будет выполнена реструктуризация, а затем основной поток продолжит выполнение. А на самом деле поток реструктуризации и основной поток работают одновременно. Кто-кого из этих потоков обгонит — не известно.
Фигово только когда реструктуризации медленней.
Б> Вариантов несколько. Б> Первый — убрать асинхронность (ProgressWorker.Run), т.е. пустить синхронизацию в основном потоке.
UI не понравится. Б> Второй — синхронизировать два потока между собой. Я приводил код в [url=http://rsdn.ru/Forum/Message.aspx?mid=4282418&only=1]Re: Ошибки первого запуска
[/url]. Этот же код сейчас в репозитории Януса.
По моему, я понял отличия, я делал только WaitOne без DoEvents(), а без этого ProgressWorker.Run видимо не работает.
[/url]. Этот же код сейчас в репозитории Януса.
Проверено, данный подход не рабочий. Как только Application.DoEvents() появляется до Application.Run возникают разные бяки.
Для теста можно вставить строку
Application.DoEvents();
в Janus.Main
перед
DatabaseManager.CheckTopicInfoIntegrity(host);
Сразу перестает работать синхронизация и трей иконка не работает правильно (исчезают контекстное меню и реакция на двойной щелчек). Наверняка есть еще что то.
Я все еще в процессе правки, пришлось инициализацию приложения полностью переделать.
Здравствуйте, AlexNek, Вы писали:
AN>Проверено, данный подход не рабочий. Как только Application.DoEvents() появляется до Application.Run возникают разные бяки.
Не совсем так. Application.DoEvents перед Application.Run сам по себе не опасен. Я предполагаю, дело немного в другом, хотя и связано с DoEvents.
При запуске приложения
— В конструкции "using (var host = new JanusHost(rootManager))" производится поиск в сборках всех частей приложения (классов, помеченных атрибутом ActivePart) и их конструирование (вызывается конструктор). Каждая такая часть может публиковать сервисы необходимые для работы приложения. Также эти части могут обращаться к уже опубликованным сервисам.
— Далее, при выходе из конструкции "using (host.InitScope)" производится активирование всех частей приложения (вызов ActivatePart или т.п.).
— Далее, Application.Run
Проблем в следующем. Некоторые части приложения обращаются к GUI через асинхронные операции. Эти операции не выполняются сразу, а помещаются в очередь сообщений GUI для дальнейшей обработки.
Если мы выполняем все в том порядке как написано выше, то все ок: происходит создание частей, затем активирование всех частей, затем обработка сообщений которые насоздавали части в плане GUI (в Application.Run). Причем эти операции GUI выполняются в окружении, когда все части (сервисы) приложения уже работают.
Если мы вставляем DoEvents как в предложеном варианте, то мы запускаем некоторые операции GUI (в DoEvents), которые к этому времени насоздавали части приложения. При этом еще не были сформированы и активированы все сервисы приложения. В связи с этим и возникают такие проблемы.
Для подтверждения вышесказанных слов достаточно поставить DoEvents сразу после блока "using (host.InitScope)", тем самым гарантируя, что этот DoEvents будет выполнен уже после активирования всех частей приложения. В этом случае ошибок не возникает.
Варианты решения:
1. Вынести работу по проверке и созданию БД из блока using. После этого блока можно безболезненно использовать DoEvents.
2. В принципе, можно попытаться разобраться чем отличается окружение (опубликованные сервисы) при первом и последующем запуске, и исправить проблемы в сервисах, но, это трудоемко.
Вообще, описанный подход к запуску приложения, на мой взгляд, слишком сложен. Более правильный вариант был бы, если бы части приложения при запуске приложения различали бы фазы "до GUI" и "GUI". Или даже вообще всю работу выполняли когда очередь сообщений уже запущена, т.е. после Application.Run.
AN>Сразу перестает работать синхронизация и трей иконка не работает правильно (исчезают контекстное меню и реакция на двойной щелчек). Наверняка есть еще что то.
Синхронизация работает нормально после первого запуска.
С контекстным меню у иконки в трее, действительно, есть проблема.
AN>Я все еще в процессе правки, пришлось инициализацию приложения полностью переделать.
Здравствуйте, Буравчик, Вы писали:
Б>Здравствуйте, AlexNek, Вы писали:
AN>>Проверено, данный подход не рабочий. Как только Application.DoEvents() появляется до Application.Run возникают разные бяки.
Б>Не совсем так. Application.DoEvents перед Application.Run сам по себе не опасен. Я предполагаю, дело немного в другом, хотя и связано с DoEvents.
думаю, что предположение правильное, я этого просто не знал. Краду твой текст для документации.
Б>Вообще, описанный подход к запуску приложения, на мой взгляд, слишком сложен. Более правильный вариант был бы, если бы части приложения при запуске приложения различали бы фазы "до GUI" и "GUI". Или даже вообще всю работу выполняли когда очередь сообщений уже запущена, Б>т.е. после
входа в Б>Application.Run.
Я сделал по другому. "Создал еще один Application.Run" и там делаю весь апдейт базы. Иначе говоря, разделил инициализацию на ГВИ и не ГВИ части.
Можно тута глянуть, может чего напортачил. Там два новых класса InvisibleInitializationForm и JanusApplicationContext
AN>>Сразу перестает работать синхронизация и трей иконка не работает правильно (исчезают контекстное меню и реакция на двойной щелчек). Наверняка есть еще что то.
Б>Синхронизация работает нормально после первого запуска.
Попробуй Application.DoEvents вставить. У меня перестала работать.
Здравствуйте, AlexNek, Вы писали:
AN>думаю, что предположение правильное, я этого просто не знал. Краду твой текст для документации.
Я не против. Но будет лучше, если кто-нибудь (может AVK?) подтвердит, что написанное верно
AN>Я сделал по другому. "Создал еще один Application.Run" и там делаю весь апдейт базы. Иначе говоря, разделил инициализацию на ГВИ и не ГВИ части. AN>Можно тута глянуть, может чего напортачил. Там два новых класса InvisibleInitializationForm и JanusApplicationContext
Посмотрю. Так или иначе, переделывать запуск когда-нибудь придется
Б>>Синхронизация работает нормально после первого запуска. AN>Попробуй Application.DoEvents вставить. У меня перестала работать.
Пробовал — синхронизация работает. Хотя это и не важно, т.к. надо решать все в комплексе.
Здравствуйте, Буравчик, Вы писали:
Б>Здравствуйте, AlexNek, Вы писали:
AN>>думаю, что предположение правильное, я этого просто не знал. Краду твой текст для документации.
Б>Я не против. Но будет лучше, если кто-нибудь (может AVK?) подтвердит, что написанное верно
Конечно, не помешает. Но мне кажется, что рассуждения резонные.
Б>>>Синхронизация работает нормально после первого запуска. AN>>Попробуй Application.DoEvents вставить. У меня перестала работать.
Б>Пробовал — синхронизация работает. Хотя это и не важно, т.к. надо решать все в комплексе.
А у меня ошибки не появляются и бывало окно просто застывало. Но важно, что при данном подходе все же появляются проблемы.
Я пока буду потихоньку тестировать, что сделал, одну ошибку как раз нашел (при показе ошибок нельзя без огляки пользоваться сервисом UIShell, его может еще просто не быть.)