Tenho o seguinte cenário:
Inicio uma thread que de tempos em tempos realiza um processo de sincronização de horário, nesta thread utilizo um .sleep() de 5 segundos para não usar todo o recurso da máquina. A fim de validar este procedimento, alterei o horário da máquina para verificar se a sincronização era realizada. Ao alterar o relógio para o futuro, o processo funciona, porém, ao atrasar o relógio a execução para no Thread.Sleep(5000). Isso só está ocorrendo no SO Linux, no windows não consegui reproduzir este problema, porém preciso que funcione no linux.
Alguém saberia se tem algo que possa resolver este problema? porque o java responde desta forma?
Lembrando que o processo que uso para sincronizar o horário não chega a ser executado, então não tem relação ao problema. Mesmo porque qualquer Thead.Sleep() fica congelado.
Nova descoberta. Testei em Ubuntu e o thread.sleep() não parou. Mas no fedora o problema acontece, e tenho a necessidade que funcione nele. Será que o marcobiscaro2112 ou alguém conseguiria testar no fedora ?
Sobre a página do bug , nela está citando CLOCK_MONOTONIC, onde pelo que entendi através dele o calculo de hora não sofre alterações. Pelo java, conforme pesquisei é acessado via System.NanoTime(), porém não consegui vincular essa funcionalidade para Thread.Sleep().
Meu ambiente é:
java -version
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.2) (fedora-43.1.8.2.fc13-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)
uname -a
Linux 2.6.34.7-61.fc13.x86_64 #1 SMP Tue Oct 19 04:06:30 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux
Com wait ocorre o mesmo problema.
Talvez o usuário que postou sobre o wait não tenha percebido um detalhe. Se o relógio for atrasado e neste momento a thread não está parada no wait, o problema não ocorre, ou seja , quando ele parar no wait, vai esperar os milissegundos do parametro e sair normal, porém, se o atraso do relógio for gerado no momento em que a execução estiver parada no wait, ai sim o problema ocorre. Após perceber isso também verifiquei no caso do Thread.Sleep() e percebi que essas condições também acontecem para ele.
Puxa - será que tal bug só foi corrigido no Linux 32 bits? É que o Ubuntu do Marco Biscaro é em 32 bits.
(A propósito, não tenho aqui uma máquina com Linux em que eu tenha acesso administrativo para testar. Não consigo lhe afirmar nada - embora seja perfeitamente possível baixar os fontes do OpenJDK para ver se o pessoal da saudosa Sun corrigiu mesmo isso em 64 bits também.)
[quote=entanglement]Puxa - será que tal bug só foi corrigido no Linux 32 bits? É que o Ubuntu do Marco Biscaro é em 32 bits.
(A propósito, não tenho aqui uma máquina com Linux em que eu tenha acesso administrativo para testar. Não consigo lhe afirmar nada - embora seja perfeitamente possível baixar os fontes do OpenJDK para ver se o pessoal da saudosa Sun corrigiu mesmo isso em 64 bits também.)
[/quote]
Entendo.
É , olhar o jdk é uma possibilidade, embora essa resposta não iria ajudar muito pois o fato é que não está funcionando.
Também não tenho uma máquina 64 bits para testar. Mas olhando o código fonte do JDK 6, não houve mudança na implementação do sleep do build 18 para o build 20.
Aliás, no método os::sleep, caso o tempo do sistema seja mudado para o passado, ele simplesmente não altera o tempo que ainda falta para dormir:
for (;;) {
if (os::is_interrupted(thread, true)) {
return OS_INTRPT;
}
jlong newtime = javaTimeNanos();
if (newtime - prevtime < 0) {
// time moving backwards, should only happen if no monotonic clock
// not a guarantee() because JVM should not abort on kernel/glibc bugs
assert(!Linux::supports_monotonic_clock(), "time moving backwards");
// NÃO ALTERA O VALOR DE millis
} else {
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
}
if(millis <= 0) { // NO CASO DE VOLTAR O TEMPO, ISSO NÃO OCORRERÁ
return OS_OK;
}
prevtime = newtime;
{
assert(thread->is_Java_thread(), "sanity check");
JavaThread *jt = (JavaThread *) thread;
ThreadBlockInVM tbivm(jt);
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or
// java_suspend_self() via check_and_wait_while_suspended()
slp->park(millis);
// were we externally suspended while we were waiting?
jt->check_and_wait_while_suspended();
}
}
Isso significa que o mesmo problema reportado ainda ocorre caso o kernel não suporte o relógio de hardware (ou caso a JVM, por algum motivo, não reconheça o suporte). Seria esse o caso?
[quote=marcobiscaro2112]Também não tenho uma máquina 64 bits para testar. Mas olhando o código fonte do JDK 6, não houve mudança na implementação do sleep do build 18 para o build 20.
Esse método e o método os::sleep (linha 2790) estão idênticos entre o b18 e o b20.
Não encontrei nenhum indício que há distinção de métodos entre uma JVM 32 bits e uma 64 bits.
Será que não procurei direito ou o problema está em outro lugar?[/quote]
Interessante.
Eu também tenho dúvidas com relação aos métodos.
Talvez uma saída fosse verificar se o relógio monotônico está disponível na máquina, alguém sabe como se faz isso ?
Talvez ele não desse mais problema se eu conseguisse ativar isso.
[quote=vctlzac]Talvez uma saída fosse verificar se o relógio monotônico está disponível na máquina, alguém sabe como se faz isso ?
Talvez ele não desse mais problema se eu conseguisse ativar isso.[/quote]
Bem, extraindo a parte que verifica o suporte ao relógio via hardware, chegamos a isso:
# include <stdio.h>
# include <dlfcn.h>
# include <time.h>
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC (1)
#endif
int main() {
void* handle = dlopen("librt.so.1", RTLD_LAZY);
if (handle == NULL) {
handle = dlopen("librt.so", RTLD_LAZY);
}
if (handle) {
int (*clock_getres_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
int (*clock_gettime_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
if (clock_getres_func && clock_gettime_func) {
struct timespec res;
struct timespec tp;
if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
printf("OK!\n");
} else {
printf("Sem suporte...\n");
}
}
dlclose(handle);
}
}
Você pode compilar e executar isso nas duas máquinas (lembrando que é preciso compilar uma vez em cada máquina - 32 e 64 bits):
[quote=vctlzac][quote=marcobiscaro2112][quote=vctlzac]Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?[/quote]
O mesmo aqui. Você testou no Fedora 64 bits?[/quote]
Sim , este valor 200809 foi gerado no fedora 64 bits.
Só pra eu entender, valores diferentes de 200112 representam problema ?[/quote]
Se representarem, estou com um problema. Mas quando voltei o relógio do sistema a Thread retomou de forma correta. Você rodou o código que postei?
[quote=marcobiscaro2112][quote=vctlzac][quote=marcobiscaro2112][quote=vctlzac]Ao executar este último código, o retorno foi “200809”.
Sabe dizer o que representa ?[/quote]
O mesmo aqui. Você testou no Fedora 64 bits?[/quote]
Sim , este valor 200809 foi gerado no fedora 64 bits.
Só pra eu entender, valores diferentes de 200112 representam problema ?[/quote]
Se representarem, estou com um problema. Mas quando voltei o relógio do sistema a Thread retomou de forma correta. Você rodou o código que postei?[/quote]
Você diz este código ?
# include <stdio.h>
# include <dlfcn.h>
# include <time.h>
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC (1)
#endif
int main() {
void* handle = dlopen("librt.so.1", RTLD_LAZY);
if (handle == NULL) {
handle = dlopen("librt.so", RTLD_LAZY);
}
if (handle) {
int (*clock_getres_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
int (*clock_gettime_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
if (clock_getres_func && clock_gettime_func) {
struct timespec res;
struct timespec tp;
if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
printf("OK!\n");
} else {
printf("Sem suporte...\n");
}
}
dlclose(handle);
}
}
Este não executei … achei que se rodasse o outro poderia descartar este.
O que esse código faz ?