Cálculo do número de segundos entre dois pontos no tempo, em cacau, mesmo quando o relógio do sistema mudou no meio

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

Pergunta

Estou escrevendo um programa de usuário final do Cocoa OS X (Leopard 10.5+) que está usando registros de data e hora para calcular estatísticas por quanto tempo algo está sendo exibido na tela. O tempo é calculado periodicamente enquanto o programa é executado usando um NSTIMER repetido. [NSDate date] é usado para capturar registros de data e hora, Começar e Terminar. Cálculo da diferença entre as duas datas em segundos é trivial.

Um problema ocorre se um usuário final ou NTP alterar o relógio do sistema. [NSDate date] depende do relógio do sistema, por isso, se ele mudou, o Terminar A variável será distorcida em relação ao Começar, bagunçando significativamente o cálculo do tempo. Minha pergunta:

1. Como posso calcular com precisão o tempo entre Começar e Terminar, em segundos, mesmo quando o relógio do sistema é alterado no meio do caminho?

Estou pensando que preciso de um ponto de referência que não mude no tempo, para que eu possa calcular quantos segundos se passaram desde então. Por exemplo, tempo de atividade do sistema. 10.6 tem - (NSTimeInterval)systemUptime, parte de NSProcessInfo, que fornece tempo de atividade do sistema. No entanto, isso não funcionará, pois meu aplicativo deve funcionar em 10.5.

Tentei criar um contador de tempo usando o NSTIMER, mas isso não é preciso. O NSTIMER possui vários modos de execução diferentes e só pode executar um de cada vez. Nstimer (por padrão) é colocado no predefinição modo corrida. Se um usuário começar a manipular a interface do usuário por um tempo suficiente, isso entrará Nseventrackingrunloopmode e pular sobre o predefinição O modo de execução, o que pode levar a disparos de NSTimer sendo ignorados, tornando -o uma maneira imprecisa de contar segundos.

Também pensei em criar um thread separado (NSRunloop) para executar uma segunda contratempo do NSTIMER, mantendo-o longe das interações da interface do usuário. Mas sou muito novo no multi-threading e gostaria de ficar longe disso, se possível. Além disso, não tenho certeza se isso funcionaria com precisão no caso de a CPU ser atrelada por outro aplicativo (o Photoshop tornando uma imagem grande, etc ...), fazendo com que meu nsrunloop seja colocado em espera por tempo suficiente para bagunçar seu Nstimer.

Agradeço qualquer ajuda. :)

Foi útil?

Solução 3

Eu descobri uma maneira de fazer isso usando o Tempo de atividade() Função c fornecida em <CoreServices/CoreServices.h>. Isso retorna tempo absoluto (específico da CPU), que pode ser facilmente convertido em tempo de duração (milissegundos ou nanossegundos). Detalhes aqui: http://www.meandmark.com/timingpart1.html (Procure na parte 3 para o tempo de atividade)

Eu não conseguia mach_absolute_time() Funcionar corretamente, provavelmente devido à minha falta de conhecimento, e não ser capaz de encontrar muita documentação na Web sobre isso. Parece pegar o mesmo tempo que UpTime(), mas convertê -lo em um duplo me deixou pasmo.

[[NSApp currentEvent] timestamp] funcionou, mas apenas se o aplicativo estivesse recebendo NSEVents. Se o aplicativo entrasse em primeiro plano, não receberia eventos e [[NSApp currentEvent] timestamp] Simplesmente continuaria retornando o mesmo registro de registro de data e hora novamente em um método de disparo do NSTIMER, até que o usuário final decidisse interagir com o aplicativo novamente.

Obrigado por toda a sua ajuda Marc e Mike! Vocês dois definitivamente me enviaram na direção certa, levando à resposta. :)

Outras dicas

Dependendo do que está impulsionando este código, você tem 2 opções:

  • Para precisão absoluta, use mach_absolute_time(). Ele dará o intervalo de tempo exatamente entre os pontos em que você chamou de função.
  • Mas em um aplicativo GUI, isso geralmente é realmente indesejável. Em vez disso, você quer a diferença horária entre o eventos Isso começou e terminou sua duração. Se sim, compare [[NSApp currentEvent] timestamp]

Ok, então isso é um tiro no escuro, mas você pode tentar implementar algo como NSSystemClockDidChangeNotification Disponível em Snow Leopard.

Portanto, tenha paciência comigo aqui, porque essa é uma idéia estranha e é definitivamente não terminal. Mas e se você tivesse um tópico de vigilância passando pela duração do seu programa? Este tópico, a cada N Segundos, lia o tempo do sistema e o armazenaria. Por uma questão de argumento, vamos apenas fazer 5 segundos. Portanto, a cada 5 segundos, ele compara a leitura anterior com o tempo atual do sistema. Se houver uma diferença "grande o suficiente" ("grande o suficiente" precisaria definitivamente ser maior que 5, mas não muito Maior, para explicar o não determinismo da programação de processos e priorização de threads), após uma notificação de que houve uma mudança de tempo significativa. Você precisaria brincar com o valor que constitui "grande o suficiente" (ou pequeno o suficiente, se o relógio foi redefinido para um tempo anterior) para suas necessidades de precisão.

Eu sei que isso é meio hacky, mas, mas exceto qualquer outra solução, o que você acha? Pode isso, ou algo assim, resolver seu problema?

Editar

Ok, então você modificou sua pergunta original para dizer que prefere não usar um tópico de vigilância porque é novo no multithreading. Entendo o medo de fazer algo um pouco mais avançado do que você se sente confortável, mas isso pode acabar sendo a única solução. Nesse caso, você pode ter um pouco de leitura para fazer. =)

E sim, eu sei que algo como o Photoshop pisando a porcaria do processador é um problema. Outra solução (ainda mais complicada) seria, em vez de ter um cão de guarda fio, tenha um cão de guarda separado processo Isso tem prioridade, por isso é um pouco mais imune ao processo de processador. Mas, novamente, isso está ficando realmente complicado.

Edição final

Vou deixar todas as minhas outras idéias acima por uma questão de completude, mas parece que o uso do tempo de atividade do sistema também será uma maneira válida de lidar com isso. Desde [[NSProcessInfo processInfo] systemUptime] Funciona apenas em 10.6+, você pode simplesmente ligar mach_absolute_time(). Para ter acesso a essa função, apenas #include <mach/mach_time.h>. Esse deve ser o mesmo valor que devolvido por NSProcessInfo.

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