#c#
#c#
Вопрос:
У нас есть консольное приложение с именем EC. Недавно мы получили требование от заказчика показать форму из этого консольного приложения. Мы отобразили форму со следующим исходным кодом
ModuleInitializerForm moduleInitializerDlg = new ModuleInitializerForm()
{
Parent = parent,
TopMost = true,
TopLevel = true,
Text = Common.MESSAGE_INFO_TITLE,
ControlBox = false,
FormBorderStyle = FormBorderStyle.FixedDialog,
KeyPreview = false,
};
moduleInitializerDlg.Initialize();
moduleInitializerDlg.ShowDialog();
Цель этой формы — отобразить статус инициализации модуля. Форма получит статус инициализации модуля как события от других компонентов. Она автоматически закрывается, когда получает событие завершения / сбоя последней инициализации модуля. Исходный код формы приведен ниже.
Проблема в том, что иногда метод OnModuleInitializationCompleted блокируется следующими записями в журнале. Первая запись в журнале взята из потока обратного вызова события, а вторая запись в журнале взята из потока формы. Согласно исходному коду, должен быть вызван метод CheckIfAllModulesInitComplete. Но этого не происходит. Можете ли вы помочь мне решить проблему?
[32][4/26/2011 17:43:15:828]- INFO-[ThreadId = 5332, OnModuleInitializationCompleted] -Полученный ЭТАП
[33][4/26/2011 17:43:15:828]- INFO-[ThreadId = 6132, OnModuleInitializationCompleted] -Полученный ЭТАП
Исходный код формы
internal partial class ModuleInitializerForm : Form
{
private List<ModuleData> _moduleDataList = new List<ModuleData>();
private List<MessageData> _messageList = new List<MessageData>();
delegate void ECEventsHandler(object sender, EventArgs e);
public ModuleInitializerForm()
{
InitializeComponent();
InitializeFootPrintControl();
}
internal void Initialize()
{
IEquipmentControl equipMentControl = null;
ConnectToEquipmentControl(out equipMentControl);
ReadOnlyCollection<IModule> moduleList = equipMentControl.GetAllModules();
foreach (IModule module in moduleList)
{
this._moduleDataList.Add(new ModuleData(module));
module.InitializationStarted = new EventHandler(OnModuleInitializationStarted);
module.InitializationCompleted = new EventHandler(OnModuleInitializationCompleted);
}
this._moduleStatusGrid.DataSource = this._moduleDataList.ToArray();
this._footprint.Activate();
}
public void OnModuleInitializationCompleted(object sender, EventArgs e)
{
ModuleStatusWindow.Logger.LogMessage("OnModuleInitializationCompleted", LogMessageType.Information, "Received {0}", (sender as IModule).Name);
if (this.InvokeRequired)
{
this.BeginInvoke(new ECEventsHandler(OnModuleInitializationCompleted), sender, e);
}
else
{
CheckIfAllModulesInitComplete();
}
}
private void CheckIfAllModulesInitComplete()
{
ModuleStatusWindow.Logger.LogMessage("CheckIfAllModulesInitComplete", LogMessageType.Information, "Enter >>");
this._moduleStatusGrid.DataSource = this._moduleDataList.ToArray();
this._moduleStatusGrid.Invalidate();
ModuleStatusWindow.Logger.LogMessage("CheckIfAllModulesInitComplete", LogMessageType.Information, "Updated grid control...");
if (this._moduleDataList.Count(moduleData => !moduleData.IsInitOver) == 0)
{
this._footprint.DeActivate();
ModuleStatusWindow.Logger.LogMessage("CheckIfAllModulesInitComplete", LogMessageType.Information, "Stopping message listenr...");
ClientMessageListner.Stop();
ModuleStatusWindow.Logger.LogMessage("CheckIfAllModulesInitComplete", LogMessageType.Information, "Closing Window...");
this.Close();
}
ModuleStatusWindow.Logger.LogMessage("CheckIfAllModulesInitComplete", LogMessageType.Information, "Leave <<");
}
public void OnModuleInitializationStarted(object sender, EventArgs e)
{
ModuleStatusWindow.Logger.LogMessage("OnModuleInitializationStarted", LogMessageType.Information, "Received {0}", (sender as IModule).Name);
if (this.InvokeRequired)
{
this.BeginInvoke(new ECEventsHandler(OnModuleInitializationStarted), sender, e);
}
else
{
ModuleStatusWindow.Logger.LogMessage("OnModuleInitializationStarted", LogMessageType.Information, "Updating the grid...");
this._moduleStatusGrid.DataSource = this._moduleDataList.ToArray();
this._moduleStatusGrid.Invalidate();
ModuleStatusWindow.Logger.LogMessage("OnModuleInitializationStarted", LogMessageType.Information, "Updated module status grid.");
}
}
private void ConnectToEquipmentControl(out IEquipmentControl equipMentControl)
{
ServerConfig equipmentConfig = ICECommonInterface.GetServerConfiguration("ICEEquipmentControl");
TcpChannel clientChannel = null;
equipMentControl = RemoteConnectionManager.RegisterClient<IEquipmentControl>(equipmentConfig, out clientChannel);
}
private void InitializeFootPrintControl()
{
this._footprint.ImportConfiguration(ICECommonInterface.ConfigPath @"FootPrintConfig.xml");
this._footprint.Initialize();
}
}
Комментарии:
1. Приятное краткое резюме. Можете ли вы удалить что-нибудь, что никогда не использовалось? И какие потоки вы здесь запускаете?
2. Хенк Холтерман — Я удалил некоторый код и комментарии, чтобы сделать код очень простым
3. Вы уверены, что у вас здесь действительно проблема с «блокировкой». Или сообщения, которые вам нужны для закрытия окна, не принимаются?
4. Я уверен, что CheckIfAllModulesInitComplete не вызывается из OnModuleInitializationCompleted, потому что в файлах журнала нет записей журнала из этого метода. Итак, я чувствую, что есть какая-то проблема зависания
Ответ №1:
Согласно вашему коду и некоторым вашим описаниям в ветке комментариев, похоже, что ваша проблема заключается в том, что события не фиксируются, и, в свою очередь, метод ‘OnModuleInitializationCompleted’ не может быть вызван. Конечно, модель потоков играет определенную роль во всем этом.
Одиночный поток:
У вас есть консольное приложение, которое, вероятно, работает из одного потока, поэтому ваша проблема в том, что само диалоговое окно блокирует инициализацию модулей. Взгляните на приведенный ниже псевдокод….
modDialog.Initialize();
// This is a blocking call. The program will wait until the dialog is closed!
modDialog.ShowDialog();
// This is where the mods are initialized, but it is waiting for the dialog to close,
// and the dialog is waiting on the initialization of the modules.
InitModules();
Конечно, мне, вероятно, не нужно упоминать, что смешивать диалоговые окна с консольными приложениями просто глупо, но необходимость, я полагаю, создает странных партнеров….
Вот несколько вариантов:
1. Используйте консоль для отображения сообщений инициализации, а не диалогового окна. (лучше всего)
2. Используйте диалоговое окно.Show(), который не блокируется, но пользователь может закрыть его, если захочет (лучше)
3. Запустите инициализацию каждого из модулей из самого диалогового окна (полный взлом)
Многопоточность:
С другой стороны, такого рода вещи в многопоточном коде может быть действительно сложно увидеть. Например, ваши обработчики событий могут быть действительными, но к моменту их настройки события, которые они намереваются перехватить, уже запущены, и поэтому вы фактически их не перехватываете.
Комментарии:
1. @A.R- Метод InitModules будет вызван из другого потока. Форма иногда закрывается. Иногда она не закрывается. Из файлов журнала я знаю, что эта форма получила все события завершения инициализации модуля
2. Из журнала я вижу, что вызов OnModuleInitializationCompleted вызывается для всех модулей. Но, как я упоминал в первом сообщении, CheckIfAllModulesInitComplete не вызывается для последнего модуля из OnModuleInitializationCompleted. Это меня смущает
3. @Maanu — Прерывистый характер вашей проблемы (иногда это срабатывает) предполагает, что у вас какой-то тип состояния гонки. Возможно, вам следует попробовать однопоточный подход к инициализации в качестве доказательства концепции.