Pergunta

Eu fiz um pouco de programação em Windows, mas agora eu tenho que escrever o meu primeiro aplicativo Linux.

Eu preciso falar com um dispositivo de hardware usando UDP. I ter de enviar pacotes de 60 por segundo com um tamanho de 40 bytes. Se eu enviar menos de 60 pacotes dentro de 1 segundo, as coisas ruins vão acontecer. Os dados para os pacotes pode levar algum tempo, para gerar. Mas se os dados não está pronto para enviar para fora no fio, é ok para enviar os mesmos dados que foram enviados pela última vez. O computador é apenas uma linha de comandos de configuração e só vai executar este programa.

Eu não sei muito sobre Linux, então eu estava esperando para ter uma idéia geral como você pode configurar um aplicativo para atender a esses requisitos. Eu estava esperando por uma resposta como:

Faça 2 fios, um para pacotes de envio e outro para os cálculos.

Mas eu não tenho certeza que é assim tão simples (talvez seja). Talvez seria mais confiável para fazer algum tipo de daemon que apenas enviou pacotes de memória compartilhada ou algo assim e, em seguida, ter um outro app fazer os cálculos? Se for alguma solução processo múltipla, que mecanismo de comunicação que você recomendaria? Existe alguma maneira eu posso dar meu aplicativo mais prioridade do que o normal ou algo semelhante?

PS: Quanto mais à prova de balas melhor

Foi útil?

Solução

Eu postei esta resposta para ilustrar uma abordagem completamente diferente para o "óbvio" um, na esperança de que alguém descubra que ele seja exatamente o que precisam. Eu não esperava que ele seja selecionado como a melhor resposta! Trate esta solução com cautela, pois existem potenciais perigos e problemas de concorrência ...

Você pode usar o href="http://linux.die.net/man/2/setitimer" rel="nofollow noreferrer"> setitimer () chamada de sistema para ter um SIGALRM (alarme

Um conjunto de manipuladores de sinais padrão são instalados pelo sistema operacional quando o programa começa, mas você pode instalar um manipulador de sinal personalizado usando sigaction () .

Então tudo que você precisa é de um único segmento; usar variáveis ??globais para que o manipulador de sinal pode acessar as informações necessárias e enviar um novo pacote ou repetir o último pacote conforme o caso.

Aqui está um exemplo para o seu benefício:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
int ticker = 0;

void timerTick(int dummy)
{
    printf("The value of ticker is: %d\n", ticker);
}

int main()
{
    int i;

    struct sigaction action;
    struct itimerval time;

    //Here is where we specify the SIGALRM handler
    action.sa_handler = &timerTick;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    //Register the handler for SIGALRM
    sigaction(SIGALRM, &action, NULL);

    time.it_interval.tv_sec = 1;       //Timing interval in seconds
    time.it_interval.tv_usec = 000000; //and microseconds
    time.it_value.tv_sec = 0;  //Initial timer value in seconds
    time.it_value.tv_usec = 1; //and microseconds

    //Set off the timer
    setitimer(ITIMER_REAL, &time, NULL);

    //Be busy
    while(1)
        for(ticker = 0; ticker < 1000; ticker++)
            for(i = 0; i < 60000000; i++)
                ;
}

Outras dicas

Eu fiz um projeto semelhante:. Um simples software em um computador Linux embutido, o envio de mensagens CAN a uma velocidade normal

Gostaria de ir para a abordagem de dois threads. Dê o fio enviar uma prioridade ligeiramente maior, e torná-lo enviar o mesmo bloco de dados, mais uma vez, se o outro segmento é lento no cálculo desses blocos.

60 pacotes UDP por segundo é muito relaxado na maioria dos sistemas (incluindo os embutidos), então eu não iria gastar muito suor na otimização do compartilhamento dos dados entre os fios e o envio dos pacotes.

Na verdade, eu diria: mantê-lo simples ! I você realmente é o único aplicativo no sistema, e você tem controle razoável sobre esse sistema, você não tem nada a ganhar com um esquema IPC complexo e outros truques. Mantê-lo simples irá ajudá-lo a produzir um código melhor com menos defeitos e em menos tempo, o que realmente significa mais tempo para testar.

Dois tópicos como você já sugeridas iria funcionar. Se você tem um pipe () entre eles, então seu segmento cálculo pode fornecer pacotes quando eles são gerados, enquanto seus usos comms rosca selecionar () para ver se há quaisquer novos dados. Se não, então ele simplesmente envia o último dele de cache.

Talvez eu tenha mais simplificado a questão um pouco ...

A sugestão de usar um par de sons fios como ele vai fazer o truque, enquanto a carga de realizar os cálculos não é muito grande.

Em vez de usar o pipe() como sugerido por Cogsy, eu estaria inclinado a usar um mutex para bloquear um pedaço de memória que você usa para conter a saída de seu segmento de cálculo -. Usá-lo como uma área de transferência entre as linhas

Quando seu segmento cálculo está pronto para a saída para o buffer que iria agarrar a exclusão mútua, escreve para o buffer de transferência e liberar o mutex.

Quando seu segmento de transmissão estava pronto para enviar um pacote que vai "tentar" para travar o mutex. Se ele recebe o bloqueio, dê uma cópia do buffer de transferência e enviá-lo. Se não obter o bloqueio, enviar a última cópia.

Você pode controlar a prioridade do seu processo usando "agradável" e especificando uma figura ajuste negativo para dar-lhe maior prioridade. Note que você terá que fazer isso como superusuário (ou como root, ou usando 'sudo') para ser capaz de especificar valores negativos.


edit: Esqueci de acrescentar - este é um bom tutorial sobre pthreads no linux . Também descreve o uso de semáforos.

Eu não entendo muito bem o quão difícil é a sua 60 pacotes / exigência seg. Será que uma explosão de 60 pacotes por segundo preenchimento do requisito? Ou é uma afiada 1/60 segundos de intervalo entre cada pacote necessário?

Isso pode ir um pouco fora de tópico, mas uma outra questão importante é como você configurar a caixa de Linux. Eu iria me usar um em tempo real do kernel Linux e desativar todos os serviços desnecessários. Outro sábio há um risco real de que a sua aplicação perde um pacote em algum momento, independentemente do que a arquitetura que você escolher.

De qualquer forma, dois tópicos devem funcionar bem.

Dois tópicos iria funcionar, você precisa ter certeza de que você trava sua estrutura de dados compartilhados por meio de modo que o fio de envio não vê-lo a meio de uma atualização.

60 por segundo não soa muito complicado.

Se você está realmente preocupado com a programação, definir política de escalonamento do segmento de envio para SCHED_FIFO e mlockall () sua memória. Dessa forma, nada será capaz de pará-lo enviando um pacote (que ainda podia sair tarde mas se outras coisas estão sendo enviados no fio ao mesmo tempo)

Tem de haver alguma tolerância do dispositivo - 60 pacotes por segundo é bom, mas o que é a tolerância do dispositivo? 20 por segundo? Se o dispositivo falhará se ele não receber um, eu enviá-los em três vezes a taxa que ele exige.

Gostaria de ficar longe de segmentos e processos de uso e (talvez) sinais e arquivos. Desde que você diz "coisas ruins" pode acontecer se você não enviar, você precisa evitar travamentos e condições de corrida. E que é mais fácil fazer com processos e dados separados salvos em arquivos.

Algo ao longo da linha de salvar um processo de dados para um arquivo, em seguida, renomeá-lo e começar de novo. E o outro processo de pegar o arquivo atual e enviar o seu conteúdo uma vez por segundo.

Ao contrário do Windows, você pode cópia (mover) sobre o arquivo enquanto ele está aberto.

Siga longo tempo Unix melhores práticas: mantê-lo simples e modular, dissociar as ações, e deixar que as OS fazer tanto trabalho para você quanto possível

.

Muitas das respostas aqui são no caminho certo, mas acho que eles podem ser ainda mais simples:

  • Use dois processos separados, um para criar os dados e escrevê-lo para stdout, e um para ler dados a partir de stdin e enviá-lo. Deixe o básico I / O bibliotecas lidar com o fluxo de buffer de dados entre processos, e deixar o negócio OS com o gerenciamento de threads.

  • Construir o remetente básico de primeiros usando um loop temporizador e um buffer de dados falsos e obtê-lo enviando para o dispositivo na freqüência correta.

  • Em seguida, faça o remetente ler dados de stdin - você pode redirecionar dados de um arquivo, por exemplo, "Remetente

  • Construir o produtor de dados seguinte e tubulação sua saída para o remetente, por exemplo, . "Produtor | remetente"

Agora você tem a capacidade de criar novos produtores, conforme necessário, sem mexer com o lado do remetente. Esta resposta assume uma forma de comunicação.

Mantendo a resposta mais simples possível você irá obter mais sucesso, especialmente se você não é muito fluente em sistemas baseados em Linux / Unix ainda. Esta é uma grande oportunidade para aprender um novo sistema, mas não mais fazê-lo. É fácil para saltar para respostas complexas quando as ferramentas estão disponíveis, mas por que usar um trator quando uma espátula simples é suficiente. Mutex, semáforos, memória compartilhada, etc, são todos complexidade útil e disponível, mas acrescentam que você não pode realmente precisa.

Eu concordo com a abordagem de dois fios. Também gostaria de ter dois buffers estáticos e uma enumeração compartilhada. O fio de envio deve ter essa lógica.

loop
    wait for timer
    grab mutex
    check enum {0, 1}
    send buffer 0 or 1 based on enum
    release mutex
end loop

O outro fio teria essa lógica:

loop
    check enum
    choose buffer 1 or 0 based on enum (opposite of other thread)
    generate data
    grab mutex
    flip enum
    release mutex
end loop

Desta forma, o remetente tem sempre um buffer válido para todo o tempo que está enviando dados. Apenas o segmento gerador pode alterar o ponteiro de buffer e só pode fazer isso se um envio não está em andamento. Além disso, o flip enum nunca deve tomar tantos ciclos como para retardar a maior thread do remetente prioridade por muito tempo.

Obrigado a todos, eu vou estar usando o conselho everyones. Eu gostaria de poder selecionar mais respostas do que 1!

Para aqueles que estão curiosos. Eu não tenho fonte para o dispositivo, é uma proprietária bloqueado sistema. Eu não fiz o teste suficiente para ver como exigente os 60 pacotes por segundo é ainda. Isso é todos os seus docs limitados dizer é "60 pacotes por segundo". Devido à natureza do dispositivo, porém, rajadas de pacotes vai ser uma coisa ruim. Eu acho que eu vou ser capaz de fugir com o envio de mais de 60 por segundo para compensar os pacotes perdidos ocasionais ..

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