Отладка Visual Studio 2015 не работает в многопоточном приложении

В моем проекте у меня есть большая часть кода, который должен выполняться в отдельном потоке без блокировки пользовательского интерфейса. Когда отладчик попадает в точку останова внутри этого кода, VS2015 зависает в течение 5-10 секунд. После этого, если я попытаюсь продолжить отладку (нажав кнопку "Шаг за шагом", "Вперед" или "Продолжить" ), приложение переходит из приостановленного состояния в рабочее состояние, инструменты отладки галочки, но ничего не происходит и 0% загрузки ЦП. Если я нажимаю Break All, тогда "cursor" (не знаю правильного термина) отображается в Application.Run( new Form1() ); в Program.cs, где Main() есть.

Поскольку я довольно новичок в С#, я подумал, что существует некоторая проблема с моим подходом к многопоточности, но, судя по всему, все происходит независимо от того, что я пытаюсь использовать с помощью async/await с Tasks, используя компонент BackgroundWorker или простой new Thread(myFunc).Start().

Просто чтобы быть ясным.

  • Сам код работает отлично.
  • Сам отладчик также работает, без зависаний и "тупиков" на контрольных точках в моем основном потоке. Если я запускаю код из основного потока - все в порядке.
  • Я также проверил его в полностью новом решении на простой функции for ( int i = 0; i < Int32.MaxValue; ++i ) - той же самой проблеме.
  • Также проверяется на разных версиях .NET: 4.6, 4.5, 4.0. То же самое и везде.
  • Проблема не возникает ни в VS2010 (что я использовал ранее), ни в VS2013 (что я пытался просто убедиться, что это проблема VS2015). Однако мой друг, работающий с тем же VS2015, также не имеет этой проблемы.

Изменить: за запрос, код тестовой формы, где я все время получаю проблему. Только три кнопки, ярлык и 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();
    }
}

Ответ 1

У меня возникли аналогичные проблемы с замораживанием VS2015 (неопределенно) при отладке многопоточного приложения WinForms.

У меня не было проблем с отладкой того же кода в VS2013.

Проблема исчезнет, ​​когда я отключу процесс хостинга VS (Project → Properties → Debug → Включить процесс хостинга Visual Studio).

Надеюсь, что это работает для других.

Ответ 2

После того, как я проверил "использовать режим совместимой совместимости" в параметрах-отладке-генератора, отладка потоков работает.

Ответ 3

У меня были точки останова в двух разных потоках, и Visual Studio подпрыгивала от одного к другому, когда я шагнул. В конце концов он застыл с (не отвечает) в строке заголовка.

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

Ответ 4

У меня была аналогичная проблема. Другие ответы на этот вопрос не разрешили проблему для меня, но они указали мне в правильном направлении. По-видимому, у меня была выбрана конфигурация Release, а не Отладка.

Ответ 5

После раздражающих часов ответ @Haggisatonal был для меня. Большое вам спасибо!

Проблема, кажется, исчезает, когда я отключу процесс хостинга VS (Project → Properties → Debug → Включить хостинг Visual Studio процесс).

но

"Инструменты → Параметры → Отладка → Общие → Включить свойство оценки и других неявных вызовов функций"

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

Ответ 6

У меня была проблема с замораживанием visual studio 2008 даже после отключения процесса хостинга. Мне кажется, что я работаю над отключением отладки уровня адреса.

(VS2008) Инструменты (меню) → Параметры → Отладка → Общие → (снимите флажок) Включить отладку на уровне адреса.

Ответ 7

Я предлагаю вам использовать комбинацию таймера и 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
    }