Como eu faço a transferência de dados dinâmico e gerenciamento de memória em threads em C?

StackOverflow https://stackoverflow.com/questions/689514

  •  22-08-2019
  •  | 
  •  

Pergunta

Plataforma: ARM9

linguagem de programação C

Requisitos -. C simples e sem libs externos e nenhum impulso

OS - REX RTOS

Eu tenho dois threads em execução em uma plataforma embarcada -

  1. um é ao nível do motorista lidar com todo o comms e transferência de dados com o hardware.
  2. o segundo segmento executa o aplicativo que usa os dados de / para o hardware.

A idéia é separar o segmento aplicativo do fio condutor para que possamos mudar o hardware e implementação no segmento de driver de hardware, mas têm um impacto mínimo sobre o histórico da aplicação.

O meu desafio é que os dados recebidos a partir do hardware pode ser dinâmico ou seja, não sabemos antecipadamente quanta memória o histórico da aplicação deve reservar para cada solicitação de / para o hardware como isso é determinado em tempo de execução.

Eu estava pensando o fio condutor possa informar o segmento do aplicativo que há muito dados para ler. O segmento do aplicativo, em seguida, aloca a memória e solicita o fio condutor para ler os dados. É, em seguida, até o fio de aplicação de processar os dados em conformidade. Desta forma, toda a gestão da memória está dentro do segmento do aplicativo.

Foi útil?

Solução

casal opções vêm à mente:

1) malloc memória no driver, libertá-la no aplicativo. Mas ... que tendem a evitar o uso malloc em qualquer coisa que se aproxima de um requisito de tempo real. Se você tem acesso a malloc / livre, e não há preocupações "tempo real" ou problemas de fragmentação de memória (ou seja, sua pilha é grande o suficiente), então esta é uma abordagem bastante fácil. O condutor apenas envia o ponteiro alocado para o segmento aplicativo através de uma fila de mensagens eo aplicativo gratuito é a memória quando terminar. Cuidado com os vazamentos de memória.

2) Anel ou tampões circulares. O controlador gere completamente um tampão de anel de tamanho fixo e simplesmente envia uma mensagem para a aplicação quando um tampão está pronto. Veja aqui alguns detalhes: Circular tampão . Em seguida, as marcas de aplicação os dados "disponível" novamente através de uma API motorista, o que ajuda a esconder os detalhes de buffer anel do fio aplicativo. Nós usamos esta abordagem para um de nossos motoristas que tem um conjunto muito semelhante de requisitos como você descreve. Neste caso, você precisa se preocupar com a determinação da "melhor" tamanho para o buffer de anel, estouro de manipulação no motorista, etc.

boa sorte!

Outras dicas

Você não especificar um sistema operacional, mas de alguma forma você tem "threads". Exceto que um deles está no nível do driver (manipulador de interrupção) e os outros sons como um aplicativo (userland / kernel). Mas isso não igualar-se também, porque o seu motorista e aplicativo está se comunicando antes dos dados serem ainda processados.

A sua terminologia é confusa e não incentivando. É este um homebrew (RT) OS ou não?

Se você tiver um sistema operacional real, não são estabelecidos métodos para escrever drivers e dados entregar a userland. Leia a documentação ou usar um dos drivers existentes como referência.

Se este é um sistema operacional personalizado, você ainda pode se referir a outros drivers de código aberto para ideias, mas claramente não terá coisas configuradas como convenientemente. Preallocate toda a memória no código do driver, preenchê-lo com dados como ele chega, e entregá-la ao código do aplicativo. A quantidade de memória será uma função de quão rápido seu aplicativo pode processar dados, é necessária a maior quantidade de dados que você pretende aceitar, e quanto filas de dados internos para apoiar a sua aplicação.

Sendo C, eu acabei tendo que fazer o aplicativo registrar um callback com o motorista. O objetivo da chamada de retorno é para processar os dados após o motorista lê-lo do dispositivo. O motorista controla a memória de memória ou seja aloca, invoca a chamada de retorno e, finalmente, libera memória. Além disso, o retorno só tem permissão de leitura na memória. Portanto, o aplicativo deve, idealmente, basta copiar o conteúdo do buffer para a sua própria memória e saída do retorno imediato. Em seguida, ele é livre para processar os dados quando e como quiser.

Eu atualizei a documentação para torná-lo claro para usos do callback aplicativo que, presume-se quando o retorno de chamada retorna, a memória não deve mais ser considerado válido. Se o retorno de chamada é usado de qualquer outra forma, o comportamento é indefinido.

Meu primeiro pensamento seria usar buffers circulares. Aqui está um exemplo de código. Sinta-se livre para se adaptar isso para seus próprios usos. Você provavelmente não iria querer variáveis ??globais. E você não pode querer #defines:

#define LENGTH (1024)
#define MASK (LENGTH-1)
uint8 circularBuffer[ LENGTH ];
int circularBuffer_add = 0;
int circularBuffer_rmv = 0;

void copyIn( uint8 * circularBuffer, uint8 * inputBuffer, int n ) {
    int i;
    for( i = 0; i < n; i++ ) {
        circularBuffer[ circularBuffer_add ] = inputBuffer[ i ];
        circularBuffer_add = ( circularBuffer_add + 1 ) & MASK;
    } 
}

void copyOut( uint8 * circularBuffer, uint8 * outputBuffer, int n ) {
    int i;
    for( i = 0; i < n; i++ ) {
        outputBuffer[ i ] = circularBuffer[ circularBuffer_rmv ];
        circularBuffer_rmv = ( circularBuffer_rmv + 1 ) & MASK;
    } 
}

Além disso, o código acima assume que sua unidade de dados é tipo de dados "uint8". Você pode alterá-lo para que ele use algum outro tipo de dados. Ou você pode até mesmo torná-lo genérico e utilização memcpy () para copiar para o buffer circular.

A principal característica deste código é como ele lida com o suplemento e rmv ptr.


Depois de conseguir as coisas que trabalham com o código acima. eu sugiro que em algum comutação pontos sobre toda a sua lê a partir do hardware para usar de sua plataforma dirigir-memória- acesso API .

É importante para mudar para dirigir-memória de acesso porque o código acima usa um monte de ciclos em relação ao DMA que utiliza quase zero de ciclos.

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