Отладка Visual Studio 2015 не работает в многопоточном приложении
в моем проекте у меня есть тяжелая часть кода, которая должна выполняться в отдельном потоке, не блокируя интерфейс. Когда отладчик попадает в точку останова внутри этого кода, VS2015 зависает на 5-10 секунд. После этого, если я попытаюсь продолжить отладку (нажав Step Over, Step In или Continue), приложение переходит из приостановленного состояния в рабочее состояние, инструменты отладки тикают, но ничего не происходит, и есть 0% использования ЦП. Если я нажму Break All, то "курсор" (не знаю правильного термина) будет показано на Application.Run( new Form1() );
в программе.cs где Main()
есть.
поскольку я довольно новичок в C#, я думал, что есть некоторые проблемы с моим подходом к многопоточности, но, по - видимому, это происходит все, что я пытаюсь-используя async/await с задачами, используя BackgroundWorker
компонент, или просто new Thread(myFunc).Start()
.
просто для ясности.
- сам код работает прекрасно.
- сам отладчик также работает, никаких зависаний и" тупиков " на точках останова в моем основном потоке. если я запустите код из основного потока - все в порядке.
- Я также проверил его в полностью новом решении на простом
for ( int i = 0; i < Int32.MaxValue; ++i )
функция-та же проблема. - также проверено на разных версиях .NET: 4.6, 4.5, 4.0. Везде одинаково.
- проблема не появляется ни в VS2010 (который я использовал раньше), ни в VS2013 (который я пытался просто убедиться, что это проблема VS2015). моя подруга работает с той же VS2015 тоже нет эта проблема.
Edit: по запросу, код тестовой формы, где я продолжаю получать проблему. Только три кнопки, ярлык и BackgroundWorker. Общая схема аналогична коду основного проекта.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const int period = 10000;
void FuncAsync(IProgress<int> progress)
{
for ( int i = 0; i < Int32.MaxValue; ++i )
{
double part = (double)i / Int32.MaxValue;
int percent = (int)(part * 100.0);
if ( (i % period) == 0 )
progress.Report( percent );
}
}
void FuncBW(BackgroundWorker worker)
{
for ( int i = 0; i < Int32.MaxValue; ++i )
{
double part = (double)i / Int32.MaxValue;
int percent = (int)(part * 100.0);
if ( (i % period) == 0 )
worker.ReportProgress( percent );
}
}
void FuncThread()
{
for ( int i = 0; i < Int32.MaxValue; ++i )
{
double part = (double)i / Int32.MaxValue;
int percent = (int)(part * 100.0);
if ( (i % period) == 0 )
label1.Text = percent.ToString();
//yes, this one will cause exception of accessing UI from different thread
//if i press "Break" in the exception window, i will also get a 10sec freeze
}
}
private async void button1_Click(object sender, EventArgs e)
{
var progress = new Progress<int>(i => label1.Text = i.ToString() );
await Task.Factory.StartNew( () => FuncAsync( progress ),
TaskCreationOptions.LongRunning );
}
private void button2_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void button3_Click(object sender, EventArgs e)
{
Thread t = new Thread(FuncThread);
t.Start();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
FuncBW( (BackgroundWorker)sender );
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
}
}
7 ответов
Я испытал аналогичные проблемы с замораживанием VS2015 (на неопределенный срок) при отладке многопоточного приложения WinForms.
У меня не было проблем с отладкой того же кода в VS2013.
проблема исчезает, когда я отключаю процесс размещения VS (Project -> Properties -> Debug -> Enable the Visual Studio hosting process).
надеюсь, что это работает для других.
после того, как я проверил "использовать режим управляемой совместимости" в options-debugging-general, отладка потоков, похоже, работает.
У меня были точки останова в 2 разных потоках, и Visual Studio прыгала от одного к другому, когда я проходил. В конце концов он застыл (не отвечая) в строке заголовка.
Если Я ограничил точки останова только одним потоком, Я бы не испытывал проблемы.
У меня была аналогичная проблема. Других ответов на этот вопрос не решило проблему для меня, но они указали мне в правильном направлении. По-видимому, у меня был релиз конфигурация выбрана, вместо Debug.
после раздражающих часов ответ @Haggisatonal был для меня. Большое спасибо!
проблема исчезает, когда я отключаю процесс размещения VS (Проект - > свойства - > отладка - > включить хостинг Visual Studio процесс.)
но
" Инструменты - > Параметры - > отладка - > общие - > включить свойство оценка и другие неявные вызовы функций"
как в билете nother, был не решение для меня, может быть, это помогает другим temporairly
У меня была проблема замораживания visual studio 2008 даже после отключения процесса хостинга. Кажется, для меня работает отключение отладки уровня адреса.
(VS2008) Инструменты (меню) - > Параметры - > отладка - > общие- > (снимите флажок) включить отладку на уровне адреса.
Я предлагаю вам использовать комбинацию таймера и WaitHandle в коде вместо цикла for, который вызывает высокое использование ЦП. Я сделал простое изменение в вашем коде, чтобы облегчить использование процессора. Надеюсь, это поможет.
public partial class Form1 : Form
{
EventWaitHandle _waitHandle ;
System.Timers.Timer _timer;
public Form1()
{
InitializeComponent();
_waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
_timer = new System.Timers.Timer();
_timer.Interval = 100;
_timer.Elapsed += OnTimerElapsed;
_timer.AutoReset = true;
}
private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_waitHandle.Set();
}
void FuncAsync(IProgress<int> progress)
{
_timer.Start();
int percent = 0;
while (percent <= 100)
{
if (_waitHandle.WaitOne())
{
progress.Report(percent);
percent++;
}
}
_timer.Stop();
}
void FuncBW(BackgroundWorker worker)
{
_timer.Start();
int percent = 0;
while (percent <= 100)
{
if (_waitHandle.WaitOne())
{
worker.ReportProgress(percent);
percent++;
}
}
_timer.Stop();
}
void FuncThread()
{
_timer.Start();
int percent = 0;
while (percent <= 100)
{
if (_waitHandle.WaitOne())
{
if (this.InvokeRequired)
{
this.Invoke((Action)delegate { label1.Text = percent.ToString(); });
}
else
{
label1.Text = percent.ToString();
}
percent++;
}
}
_timer.Stop();
}
... your other code
}