Como depurar um único segmento no Visual Studio?

254

Eu tenho uma solução com alguns projetos. Existem vários pontos de interrupção em diferentes projetos. Quero rastrear o primeiro thread que atingiu um desses pontos de interrupção e continuar rastreando esse thread único, apesar de outros segmentos inserirem os mesmos blocos de código.

Eu sei que isso é possível através da definição de uma condição no ponto de interrupção, ou seja, nome do thread = ... ou Id do segmento = ... mas meu caso é um aplicativo ASP.NET carregado com muita carga e assim que eu me conecto a w3wp.exemuitos threads atingirá os pontos de interrupção. Eu preciso de algo como ThreadLocal<break-point>.

É possível? Se sim, como?

Xaqron
fonte
7
@ Paolo: Este aplicativo da Web funciona como o coração de um grande farm da Web e a situação do buggy é impossível de imitar nos cenários de teste.
Xaqron
Para VS 2019 talvez você deva tentar o seguinte: stackoverflow.com/a/61868591/8579563
Gozo

Respostas:

150

Os segmentos de congelamento / descongelamento são incorretos porque outros não executam nenhum código.

A maneira mais correta e utilizável é:

  1. Pressione Ctrl + A na janela de pontos de interrupção (selecione todos os pontos de interrupção).
  2. Clique com o botão direito e selecione "Filtrar ...".
  3. Digite "ThreadId = (ID do segmento atual)".

No Visual Studio 2015 e mais recente, o processo é semelhante:

  1. Pressione Ctrl + A na janela de pontos de interrupção (selecione todos os pontos de interrupção).
  2. Clique com o botão direito e selecione "Configurações ...".
  3. Marque "Condições" e selecione "Filtro" no menu suspenso
  4. Digite "ThreadId = (ID do segmento atual)".

Portanto, todos os threads são executados, mas o depurador atinge apenas o thread atual.

hzdbyte
fonte
51
Isso impede que o comando depurador "Step" entre em outros threads? Esse foi um grande problema que tive. Estou percorrendo meu segmento e, de repente, estou em uma parte do código completamente não relacionada. Eu não desenvolvo mais no Visual Studio, então não posso testar.
Matt Faus 29/05
8
Clicar com o botão direito do mouse na janela de pontos de interrupção não possui o comando "filter" ... e como você descobre o ID do thread atual? - Você está indo para a janela imediata e digitando System.Threading.Thread.CurrentThread.ManagedThreadIdou algo assim?
BrainSlugs83
5
No meu VS (2015, Community Edition), não é possível modificar as configurações de vários pontos de interrupção de uma só vez. Assim, o filtro pode ser definido apenas um por um.
robert4
5
Eu tive esse problema para sempre, e eu poderia jurar no meu último emprego que encontrei uma configuração que fazia o visual studio funcionar como um eclipse, onde você se ataria ao segmento com o qual estava trabalhando, mas não consigo encontrá-lo ou fazer qualquer referência para isso. Estou começando a me perguntar se sonhei.
stu
7
-1 porque isso permite apenas pontos de interrupção, mas não efetivamente depura: avançar / entrar não funciona dessa maneira para depurar um único encadeamento.
Serge Rogatch 11/10
338

Aqui está o que eu fiz:

  1. Defina um ponto de interrupção condicional que eu sabia que só atingiria o encadeamento que estava procurando.

  2. Quando o ponto de interrupção for atingido e você estiver no segmento desejado, na janela Threads do Visual Studio (durante a depuração, Debug -> Windows -> Threads), Ctrl+ A(para selecionar todos os segmentos) e Ctrlclique no segmento em que está atualmente . Você deve ter todos os segmentos, exceto aquele que deseja depurar selecionado.

  3. Clique com o botão direito e escolha "Congelar".

Agora, o Visual Studio passará apenas pelo thread descongelado. Parece ser muito mais lento ao fazer isso, presumivelmente porque ele precisa percorrer todos os threads congelados, mas trouxe alguma sanidade à minha depuração multiencadeada.

Matt Faus
fonte
1
Isso não funciona para mim em um contexto em que tenho cerca de 8 tarefas sendo executadas em threads diferentes. Congelo todos os outros threads e "passo adiante", mas o IDE congela por um tempo e depois pula para outro thread de qualquer maneira.
Meta-Knight
3
@ Diego: Eu não estou mais trabalhando no projeto, mas se ele congelar todos os threads, exceto um, mudará o cenário que causou o bug, uma vez que os threads eram complementares na situação de buggy. Embora essa seja uma solução elegante, parece que esse recurso deve ser incorporado ao VS.
Xaqron
3
@ Meta-Knight Você deve congelar todos os tópicos, exceto o Tópico Principal. Se você vai fazer como esta IDE não será congelado
Alex Zhukovskiy
15

Acabei de lançar uma extensão do Visual Studio 2010 ou superior que faz exatamente o que você está procurando. E é grátis :).

Apresentação

Essa extensão do Visual Studio adiciona dois atalhos e botões da barra de ferramentas para permitir que os desenvolvedores se concentrem facilmente em threads únicos enquanto depuram aplicativos multithread.

Reduz drasticamente a necessidade de entrar manualmente na janela Threads para congelar / descongelar todos os threads, exceto aquele que precisa ser seguido e, portanto, ajuda a melhorar a produtividade.

Recursos

Restrinja a execução adicional apenas ao encadeamento atual. Congelará todos os outros threads. Atalho: CTRL + T + T ou botão Floco de neve. Alterne para o próximo thread único (com base no ID). Mudará o thread atual e congelará todos os outros threads. Atalho: CTRL + T + J ou botão Avançar.

Confira aqui na Galeria , na página oficial ou no repositório do Github .

Erwin Mayer
fonte
Qual versão do VS você está usando?
precisa
Instalei a extensão, mas não consegui fazê-la funcionar (no meu projeto atual, uso o VS2010). [A propósito, o que eu pensava ser um problema com os threads se tornando ativos só acontece quando os threads são criados, é provavelmente um comportamento padrão, por isso removi meu comentário anterior].
Wip 12/11/2013
3
Eu vou verificar isso. Você pode ser a única pessoa no planeta que fez qualquer tentativa de resolver uma das maiores falhas de depuração da Microsoft.
Stu
infelizmente, ele não será instalado no vs2012. Você tem uma versão mais recente ou deseja compartilhar o código-fonte para que eu possa construí-lo?
19415
@stu O código fonte está no Codeplex aqui: singlethread.codeplex.com deve funcionar no VS 2012 e no VS 2013, mas não o atualizei (ninguém solicitou e eu não precisei). Se você pode fazê-lo funcionar facilmente com o VS 2012+ e fazer uma confirmação no Codeplex, também posso enviá-lo na Galeria.
Erwin Mayer
13

Se vários threads estiverem sendo gerados como em um aplicativo da Web, as respostas do @MattFaus não funcionarão. o que eu fiz é o seguinte

  • Configure um ponto de interrupção para interromper o thread na função que eu quero.
  • Quando o thread chega ao ponto de interrupção e é pausado, removo o ponto de interrupção e continuo depurando usando F8, F10 e F11, para que os outros threads possam ser executados.
Mikaël Mayer
fonte
Depois de ler todas as principais perguntas, esta solução alternativa funcionou para mim.
Swanand Pangam
9

Uma abordagem um pouco diferente que eu usei:

  1. Crie um ponto de interrupção normal e deixe-o atingir
  2. Procure na janela de threads o ID do thread gerenciado que você está depurando no momento
  3. Clique com o botão direito do mouse no ponto de interrupção na janela de pontos de interrupção e no filtro seletor
  4. Digite ThreadId = xxx, em que xxx é o ID do encadeamento de 2
  5. Agora você pode depurar sem parar outros threads e sem que eles atinjam seu ponto de interrupção

Isso pressupõe que você tenha tempo para fazer o procedimento acima antes que um segundo thread atinja seu ponto de interrupção. Se não, e outros threads atingem seu ponto de interrupção antes de fazer o acima, clique com o botão direito do mouse na janela de threads e escolha congelar.

Matt
fonte
3
+1. "Isso pressupõe que você tenha tempo ... antes que um segundo thread atinja seu ponto de interrupção". Envolvo um ponto e vírgula em uma fechadura e coloco um ponto de interrupção no ponto e vírgula. Quando o ponto de interrupção é atingido pela primeira vez, desativo o ponto de interrupção. Nenhum outro encadeamento pode entrar devido ao bloqueio. lock(m_someObject) { ; }
Bluedog #
Para salvar um Google, a janela de threads é encontrada em Debug> Windows> Threads.
Gabe
2

No VS 2019:

  1. Defina um ponto de interrupção em algum lugar.
  2. Aperte F5 (Continuar) até que seu tópico chegue.
  3. Clique no ponto de interrupção para removê-lo.
  4. Você pode passar o fio com F10 ou F11.
Gozo
fonte
Também funciona para o VS2015!
prehistoricpenguin
1

Sugiro adicionar outra instância do aplicativo no servidor ativo, no mesmo hardware ou em uma nova máquina (agrupe-a) e depois depure apenas essa instância. Eu não adicionaria um ponto de interrupção no código que os usuários estão acionando. Se isso não for uma opção, eu adicionaria mais rastreamentos.

No entanto, se isso for absolutamente necessário e você precisar de uma estatística da solução, tenho certeza de que poderá adicionar um ponto de interrupção que interrompa apenas se a solicitação vier do seu endereço IP. Você faria isso adicionando um ponto de interrupção condicional que inspeciona HttpContext.Request.UserHostAddress. Observe, no entanto, que isso torna o aplicativo consideravelmente mais lento.

steinar
fonte
Foi o que eu tentei. O problema é que essa instância não está funcionando no mesmo domínio (em execução em IP ou outro domínio) e isso leva a muitos problemas de certificado (SSL, WCF, ...) e também com carga baixa, a situação do buggy nunca acontece!
Xaqron 14/03
Desculpe, não tenho certeza de qual deles você tentou, tentou o ponto de interrupção condicional?
steinar 14/03
Sim, eu os nomeei com base em seu ID gerenciado para garantir a exclusividade. Então é difícil adivinhar qual ID está atribuído e definir a condição com base em uma adivinhação. Às vezes, o palpite está próximo e às vezes leva muito tempo para entender o tópico.
Xaqron
1

Se você não deseja parar todos os outros segmentos (talvez esteja anexando o depurador do Visual Studio a um aplicativo em execução que precise responder a solicitações), use uma macro que crie e remova pontos de interrupção automaticamente.

Isso é sugerido em uma resposta à pergunta Stack Overflow "Step over" ao depurar programas multithread no Visual Studio .

No entanto, o link explica apenas como depurar linha por linha. Eu sugiro que você modifique a macro (se você estiver confortável com ela) para fazê-la modificar todos os pontos de interrupção (em um determinado intervalo de linhas, por exemplo) para parar apenas no thread atual.

kamaradclimber
fonte
1

Eu acho que isso é um pouco diferente no Visual Studio 2015. Eles mudaram algumas coisas nos pontos de interrupção, mas aqui está como aplicar a resposta aceita do hzdbyte (acima):

No ponto de interrupção na margem de codificação, clique com o botão direito do mouse> Condições> Alterar de 'Expressão condicional' para 'Filtro'. Isso permite filtrar por ThreadId.

Como alternativa, no ponto de interrupção na janela Pontos de interrupção, clique com o botão direito do mouse> Configurações> marque a caixa Condições e faça o acima.

Patelos
fonte
1

Defina uma condição de ponto de interrupção clicando com o botão direito do mouse na barra lateral da linha. Selecione "Condição" e digite o seguinte com o nome do seu segmento entre aspas:

System.Threading.Thread.CurrentThread.Name == "name_of_your_thread"

Como alternativa, você pode fazer o mesmo obtendo o "ID gerenciado" do thread na janela "Threads" e use:

System.Threading.Thread.CurrentThread.ManagedThreadId == your_managed_thread_id

James Sheridan
fonte