Простой код C # замораживает себя и все 32-битные приложения (включая VS2008), но только если он запускается под отладчиком с установленной точкой останова - PullRequest
1 голос
/ 09 октября 2010

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

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

Проблема: Когда я набираю первую букву моего имени пользователя в текстовом поле, автозаполнение немедленно завершает его.Содержимое выпадающего списка также должно измениться.Это происходит нормально, если я запускаю программу без отладчика, но если программа находится под отладчиком, все зависает - и мое приложение, и Visual Studio.Раскрывающийся список автозаполнения появляется, но он пуст.Загрузка процессора составляет 0%.Только когда я убиваю свое приложение, Visual Studio размораживается.

Что страннее, перемещение одной строки кода решает проблему, хотя семантически все одинаково.Таким образом, этот код работает:

private void txtUser_TextChanged(object sender, EventArgs e)
{
    string EnteredUserName = this.txtUser.Text.Trim();
    var Found = this._NoLocations; 
    foreach ( var usr in this._AllUsers )
        if (string.Compare(usr.FullName, EnteredUserName, StringComparison.CurrentCultureIgnoreCase) == 0)
        {
            Found = new List<Business.Location>(this._AllLocations.Where((a, b) => a.Distributor == usr.Distributor));
            break;
        }
    this.bndLocation.DataSource = Found;
}

Но это не так:

private void txtUser_TextChanged(object sender, EventArgs e)
{
    string EnteredUserName = this.txtUser.Text.Trim();
    var Found = null; 
    foreach ( var usr in this._AllUsers )
        if (string.Compare(usr.FullName, EnteredUserName, StringComparison.CurrentCultureIgnoreCase) == 0)
        {
            Found = new List<Business.Location>(this._AllLocations.Where((a, b) => a.Distributor == usr.Distributor));
            this.bndLocation.DataSource = Found;
            break;
        }
    if ( Found == null )
        this.bndLocation.DataSource = this._NoLocations;
}

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

Что дает?

О, почти забыл - я использую Visual Studio 2008 и Telerik RadControls Q3 2009.Это не произошло со стандартными элементами управления Windows, оно появилось только после миграции.Тем не менее, очень странно.

Обновление 1: ОК, поэтому второй фрагмент кода работает только иногда .Но вот кое-что более странное: не только VS2008 зависает.Мой браузер (Opera) и Windows Live!Мессенджер тоже стал не отвечать.К счастью, диспетчер задач и панель задач работают просто отлично.Это становится все более запутанным ...

Обновление 2: Переменные _AllUsers, _AllLocations и _NoLocations являются простыми обобщенными List<T> с.Классы User и Location являются простыми объектами с простыми свойствами.Хотя я использую NHibernate, они могут быть автоматически разделены на что-либо.bndLocation - это стандартный .NET BindingSource, к которому привязан раскрывающийся список Locations.

Обновление 3: Ух, очевидно все 32-битные процессы заморожены ,Или, по крайней мере, те, с интерфейсом.Я могу запускать новые приложения, и им удается инициализировать и показать, но затем они зависают.Для записи, я использую Windows 7 x64.

Обновление 4: Вот подвох для Обновления 1: код работает, если в коде не установлены точки останова.Если где-либо установлена ​​точка останова, она замерзнет.Точка останова не должна быть достигнута, она просто должна быть установлена.Если я установлю точку останова после запуска программы, все будет хорошо.

Обновление 5: В соответствии с запросом, вот трассировка стека для события:

ServiceTracker.exe!ServiceTracker.Forms.Login.txtUser_TextChanged(object sender = {Telerik.WinControls.UI.RadTextBox}, System.EventArgs e = {System.EventArgs}) Line 85 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.OnTextChanged(System.EventArgs e) + 0x68 bytes    
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.RadTextBoxBase.textBoxItem_TextChanged(object sender = {Telerik.WinControls.UI.RadTextBoxItem}, System.EventArgs e = {System.EventArgs}) + 0x47 bytes 
[Native to Managed Transition]  
[Managed to Native Transition]  
Telerik.WinControls.dll!Telerik.WinControls.RadItem.OnTextChanged(System.EventArgs e = {System.EventArgs}) + 0x80 bytes 
Telerik.WinControls.dll!Telerik.WinControls.RadItem.OnPropertyChanged(Telerik.WinControls.RadPropertyChangedEventArgs e = {Telerik.WinControls.RadPropertyChangedEventArgs}) + 0xeb bytes   
Telerik.WinControls.dll!Telerik.WinControls.RadHostItem.OnPropertyChanged(Telerik.WinControls.RadPropertyChangedEventArgs e = {Telerik.WinControls.RadPropertyChangedEventArgs}) + 0x5a bytes   
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.RadTextBoxItem.OnPropertyChanged(Telerik.WinControls.RadPropertyChangedEventArgs e = {Telerik.WinControls.RadPropertyChangedEventArgs}) + 0x36c bytes 
Telerik.WinControls.dll!Telerik.WinControls.RadObject.RaisePropertyNotifications(Telerik.WinControls.RadPropertyValue propVal = {Telerik.WinControls.RadPropertyValue}, object oldValue = "", object newValue = "v") + 0x2f7 bytes  
Telerik.WinControls.dll!Telerik.WinControls.RadObject.SetValueCore(Telerik.WinControls.RadPropertyValue propVal = {Telerik.WinControls.RadPropertyValue}, object propModifier = null, object newValue = "v", Telerik.WinControls.ValueSource source = Local) + 0x5bb bytes  
Telerik.WinControls.dll!Telerik.WinControls.RadElement.SetValueCore(Telerik.WinControls.RadPropertyValue propVal = {Telerik.WinControls.RadPropertyValue}, object propModifier = null, object newValue = "v", Telerik.WinControls.ValueSource source = Local) + 0xa2 bytes  
Telerik.WinControls.dll!Telerik.WinControls.RadObject.SetValue(Telerik.WinControls.RadProperty property = {Telerik.WinControls.RadProperty}, object value = "v") + 0x9b bytes   
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.RadTextBoxItem.TextBoxControl_TextChanged(object sender = {Text = "v"}, System.EventArgs e = {System.EventArgs}) + 0x168 bytes    
System.Windows.Forms.dll!System.Windows.Forms.Control.OnTextChanged(System.EventArgs e) + 0x68 bytes    
System.Windows.Forms.dll!System.Windows.Forms.TextBoxBase.WmReflectCommand(ref System.Windows.Forms.Message m) + 0xd2 bytes 
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.HostedTextBoxBase.WndProc(ref System.Windows.Forms.Message message = {msg=0x2111 (WM_REFLECT + WM_COMMAND) hwnd=0xf0478 wparam=0x3000478 lparam=0xf0478 result=0x0}) + 0x5ac bytes    
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x46 bytes  
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 8465, System.IntPtr wparam, System.IntPtr lparam) + 0xad bytes  
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.Forms.dll!System.Windows.Forms.Control.SendMessage(int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x6c bytes 
System.Windows.Forms.dll!System.Windows.Forms.Control.ReflectMessageInternal(System.IntPtr hWnd, ref System.Windows.Forms.Message m) + 0x46 bytes   
System.Windows.Forms.dll!System.Windows.Forms.Control.WmCommand(ref System.Windows.Forms.Message m) + 0x44 bytes    
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x1fd bytes 
Telerik.WinControls.dll!Telerik.WinControls.RadControl.WndProc(ref System.Windows.Forms.Message m = {msg=0x111 (WM_COMMAND) hwnd=0xc046e wparam=0x3000478 lparam=0xf0478 result=0x0}) + 0x1ab bytes 
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.RadTextBoxBase.WndProc(ref System.Windows.Forms.Message m = {msg=0x111 (WM_COMMAND) hwnd=0xc046e wparam=0x3000478 lparam=0xf0478 result=0x0}) + 0x7a bytes    
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x46 bytes  
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 273, System.IntPtr wparam, System.IntPtr lparam) + 0xad bytes   
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m) + 0x9f bytes  
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x9e6 bytes 
Telerik.WinControls.UI.dll!Telerik.WinControls.UI.HostedTextBoxBase.WndProc(ref System.Windows.Forms.Message message = {msg=0x102 (WM_CHAR) hwnd=0xf0478 wparam=0x76 lparam=0x2f0001 result=0x0}) + 0x5ac bytes 
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x46 bytes  
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 258, System.IntPtr wparam, System.IntPtr lparam) + 0xad bytes   
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason, int pvLoopData) + 0x5c3 bytes  
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = 4, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.Application.ModalApplicationContext}) + 0x578 bytes 
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x65 bytes    
System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner) + 0x763 bytes    
ServiceTracker.exe!ServiceTracker.Forms.Login.Authentificate(out ServiceTracker.Business.User user = null, out ServiceTracker.Business.Location location = null) Line 30 + 0x12 bytes   C#
ServiceTracker.exe!ServiceTracker.Framework.Program.Main() Line 79 + 0x19 bytes C#
[Native to Managed Transition]  
[Managed to Native Transition]  
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x47 bytes  
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x9b bytes    
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x4d bytes   

Обновление 6: Итак, я дошел до того, что сильно подозреваю, что где-то между моим приложением и другими 32-разрядными приложениями существует комбинация тупика и состояния гонки.Что странно, потому что даже под отладчиком процесс 64-битный.В любом случае, вот несколько возможных сценариев, которые воспроизводят проблему:

  • Метод изменяет содержимое раскрывающегося списка, и в моем коде есть точка останова ВСЕГДА.Однако, если точка останова находится за пределами оператора if в вышеприведенном методе, все работает.Возможно, это связано с тем, что точка останова попадает дважды подряд - сначала при вводе первой буквы;второй, когда автозаполнение предоставило оставшееся имя пользователя.
  • Если метод не изменяет содержимое раскрывающегося списка, но в операторе if есть точка останова, все также зависает.
  • Если метод содержит только Thread.Sleep(1000);, происходит остановка ровно на 1 секунду;
  • В противном случае нет заморозки.

Таким образом, он пахнет, как обработчик событий (или, скорее, какой-то метод в стеке) захватывает некоторый глобальный ресурс, который нужен всем другим 32-битным процессам. Поскольку VS2008 - это 32-битный процесс, он должен ждать. Но поскольку существует точка прерывания, мое приложение тоже не запускается, следовательно, тупик. Кроме того, изменение содержимого раскрывающегося списка пытается захватить ту же блокировку, и поэтому в моем приложении возникает тупик. Однако, если заранее есть пауза (когда точка останова дважды удаляется), условие гонки не наступает, и все работает снова.

Но ... я не могу представить, каким мог бы быть этот глобальный ресурс.

Ответы [ 2 ]

1 голос
/ 09 октября 2010

Я не знаю, в чем ваша проблема, но я могу указать на некоторые вещи, которые вы делаете, которые могут вызывать проблемы:

  1. Доступ к измененному замыканию в лямбда-выражении:

Вы не должны обращаться к «usr» в лямбда-выражении, поскольку это замыкание в цикле foreach, и вы можете получить здесь действительно странное поведение.(Значение «usr» будет взято в качестве последнего вместо того, с которым оно было создано.

Мне не кажется, что это будет вашей проблемой. Чтобы увидеть, если это так, сделайтеэто:

var usrTemp = usr;
Found = new List<Business.Location>(this._AllLocations.Where((a, b) => a.Distributor == usrTemp.Distributor));
  1. Я не знаю, каким провайдером LINQ вы пользуетесь или как выглядят ваши события OnItemBound, но в первом примере вы ожидаете своих товаров, когда у вас все еще естьитератор, открытый в _AllUsers. Если ваш бизнес-уровень не предназначен для поддержки этого одновременного доступа, это может вызвать проблему.

Чтобы увидеть, если это проблема, измените цикл foreach:

foreach (var usr in this._AllUsers.ToArray())
0 голосов
/ 09 октября 2010

Исключили ли вы опции d'oh, например, достижение точки останова в свойстве аксессора (возможно, в другом потоке) для this.bndLocation.DataSource?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...