Pergunta

Estamos usando C para construir um sistema de BRAÇO central (i.e.um sistema embarcado).A questão é:como podemos evitar a reentrada problema de uma maneira formal, de modo a que estamos confiantes de que todos os reentrada erros são removidos.Isso pode não ser prático deseja, mas certamente importante para qualquer sistema, eu acho.

Apenas para a discussão, eu acho que o desenho de diagrama UML ou ter uma completa máquina de estado seria um bom começo (mas como gerá-lo DEPOIS de todo o sistema é desenvolvido?).Todas as sugestões sobre como utilizar a máquina de estado / diagrama UML para fazer a análise?

Foi útil?

Solução

Eu não sei exatamente sobre o problema que você quer resolver, mas deixe-me dar um palpite.

O primeiro ponto é identificar as funções que pode ser problemático.Uma reentrada acontece por chamadas recursivas, que pode ir ao longo de várias chamadas aninhadas e até mesmo ser oculto, retornos de chamada/injeção de dependência, ou por funções que são utilizados em vários segmentos.

Você pode desenhar um dirigido gráfico de chamada.Dizer chamadas de função A B e C, em função de B chama D, e e F, a função C chamadas de nada, e assim por diante.Desenhar isso para cada thread quando multithreading.Se existem ciclos no gráfico e, em seguida, todas as funções, tornando esse ciclo precisa ser reentrada segura.Você pode ignorar sub-filiais neste caso.Funções que são usados em vários segmentos precisam ser seguras, muito, mas agora incluindo todos os sub-filiais, porque você não sabe exatamente onde cada thread é atualmente.As coisas vão se complexo e complicado, quando os bloqueios são usados, por isso, vamos ignorar isso por agora.

Esta etapa pode certamente ser automatizados através de ferramentas de análise de código.

Agora que as funções são identificadas,

  • Funções que só dependem de sua função-local de dados são geralmente seguros.Esta é uma das melhores propriedades de programação funcional.
  • Funções que dependem de dados externos (não dentro do escopo da função) deve ser examinada de perto, é especialmente importante para saber quando e onde os dados externos é alterado.
  • Funções alterar dados externos devem levantar uma bandeira vermelha e ativar a sirene do alarme alto, especialmente quando multithreading.

Outras dicas

Corrigir rápido, se você suspeitar de algo:

int some_func(int x, int y)
{
    static volatile int do_not_enter_twice = 0;
    assert(!(do_not_enter_twice++));

    /* some_func continued */

    do_not_enter_twice--;
    return whatever;
}

Resposta mais longa:
Use alguma ferramenta para fazer um Gráfico de chamada e continue manualmente a partir daí.

Uma ferramenta que pode calcular enorme Os gráficos de chamada é o DMS Software Reengeneering Toolkit e seu front end. O front -end C é usado para analisar o código C; O DMS possui máquinas incorporadas para calcular o controle e a análise do fluxo de dados, a análise de pontos e extrair fatos diretos de chamada e indiretos-indiretos-thru-thru-ponte

O DMS tem sido usado para criar gráficos de chamada para sistemas de código -fonte C de 35 milhões Linhas de código C (= 250.000 funções) e, em seguida, extrair informações desse gráfico de chamadas. Uma questão-chave ao criar gráficos grandes como esse é calcular os pontos-para obter informações com a precisão da prática (existem limitações de teoria difícil para fazer isso perfeitamente) para que as chamadas de função indireta sejam direcionadas de forma conservadora para um número mínimo de alvos falsos positivos.

No seu caso, as informações a serem extraídas são, como outros autores indicam: "Existe um ciclo?" Neste gráfico de chamada.

Nessa escala, você não deseja fazer isso manualmente e precisa refazê-lo toda vez que se prepara para uma construção de produção. Portanto, mecanizar o cheque faria muito sentido.

Eu gostaria de fazer 2 coisas para verificar o seu código.Completo código de grupo-revisão (com o objetivo de encontrar readmissão erros, não só, de estilo ou de outros erros).Em segundo lugar, um ataque prática na solução de problemas.

Por exemplo:

int myfunction(int x, int y) {
    REENTRANCE_CHECK;
    ... body of function
}

Agora você pode definir #REENTRANCE_CHECK para ser um ser vazio (para produção) ou algum código que verifica a função nunca é re-introduzida.Executar os testes (se você não tem testes, em seguida, executá-lo em seu dispositivo com o depurador anexado) com essas verificações ativadas, e ver se alguma coisa cai.

Da mesma forma, você pode adicionar depuração lógica para detectar incorreto atualizações para o estado global.Escrever código que utiliza bloqueios (que afirmar se elas são adquiridas quando já realizada.

Algo como isto:

int my_global;
DEFINE_GLOBAL_LOCK(my_global);

void my_dangerous_function() {
    ...
    LOCK_GLOBAL(my_global);
    .. some critical section of code that uses my_global.
    UNLOCK_GLOBAL(my_global);
    ...
}

Novamente, DECLARE_GLOBAL_LOCK, LOCK_GLOBAL e UNLOCK_GLOBAL pode ser #definido para ser real fecho código (que, naturalmente, você vai ter que escrever) para o teste, e para a produção podem ser #definido para nada.

Esta abordagem funciona somente se você encontrar e envolver todos os acessos ao seu estado global, mas isso é fácil com uma pesquisa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top