Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

233
Visualizações
How to create accurate nanosecond delay in a pthread and how to run a pthread part of the program without interruption?

I am a beginner in C programming. In the following code, we have two pthreads. I want one of them to be delayed at the user's choice after the two pthreads are synchronized. I want this delay to be as accurate as possible. In the following code I have done this but the exact amount of delay does not occur.

But I also have another question, and that is how can I force a pthread to run a certain part of the program from start to finish without interruption.

Thank you in advance.

code:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/random.h>
#include <sys/time.h>
#include <math.h>

pthread_cond_t cond;
pthread_mutex_t cond_mutex;
unsigned int waiting;
struct timeval timeZero, timeOne, timeZeroBase, timeOneBase;
struct timespec tim, tim2;
int flag = 0;

void synchronize(void) {
    pthread_mutex_lock(&cond_mutex);
    if (++waiting == 2) {
        pthread_cond_broadcast(&cond);
    } else {
        while (waiting != 2)
            pthread_cond_wait(&cond, &cond_mutex);
    }
    pthread_mutex_unlock(&cond_mutex);
}

void *threadZero(void *_) {
    // ...
    synchronize();
    gettimeofday(&timeZeroBase, 0);
    if(flag == 0)
        nanosleep(&tim, &tim2);
    gettimeofday(&timeZero, 0);
    timeZero.tv_usec = timeZero.tv_usec - timeZeroBase.tv_usec;
    // ...
    return NULL;
}


void *threadOne(void *_) {
    // ...
    synchronize();
    gettimeofday(&timeOneBase, 0);
    if(flag == 1)
        nanosleep(&tim, &tim2);
    gettimeofday(&timeOne, 0);
    timeOne.tv_usec = timeOne.tv_usec - timeOneBase.tv_usec;
    // ...
    return NULL;
}


int main(void) {
    pthread_t zero, one;
    tim.tv_sec  = 0;
    tim.tv_nsec = 50;
    printf("Declare the number of function (0 or 1): ");
    scanf("%d", &flag);
    pthread_create(&zero, NULL, threadZero, NULL);
    pthread_create(&one, NULL, threadOne, NULL);
    // ...
    pthread_join(zero, NULL);
    pthread_join(one, NULL);
    printf("\nReal delay (ns): %lu\n", (timeZero.tv_usec - timeOne.tv_usec));
    return 0;
}
over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

One way that may increase accuracy is to busy-wait instead of sleeping.

I've made a function called mysleep that takes a struct timespec* containing the requested sleep time. It checks the current time and adds the requested sleep time to that - and then just spins until the current time >= the target point in time.

Note though: It's not guaranteed to stay within any accuracy. It will often be rather ok, but sometimes when the OS puts the thread on hold, you'll see spikes in the measured time. If you are unlucky, the calibration will have one of these spikes in it and then all your sleeps will be totally off. You can run the calibration routine 100 times and then pick the median value to make that unfortunate circumstance very unlikely.

#include <stdio.h>
#include <time.h>

static long calib; // used for calibrating mysleep()

void mysleep(const struct timespec *req) {
    struct timespec tp, now;

    clock_gettime(CLOCK_MONOTONIC, &tp); // get current time point

    // add the requested sleep time and remove the calibrated value
    tp.tv_sec += req->tv_sec;
    tp.tv_nsec += req->tv_nsec - calib;

    if(tp.tv_nsec > 999999999) {
        tp.tv_nsec -= 1000000000;
        ++tp.tv_sec;
    } else if(tp.tv_nsec<0) {
        tp.tv_nsec += 1000000000;
        --tp.tv_sec;
    }

    // busy-wait until the target time point is reached: 
    do {
        clock_gettime(CLOCK_MONOTONIC, &now);
    } while(now.tv_sec < tp.tv_sec ||
            (now.tv_sec == tp.tv_sec && now.tv_nsec < tp.tv_nsec));
}

struct timespec get_diff(const struct timespec *start, struct timespec *end) {
    struct timespec temp;
    if((end->tv_nsec - start->tv_nsec) < 0) {
        temp.tv_sec = end->tv_sec - start->tv_sec - 1;
        temp.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec;
    } else {
        temp.tv_sec = end->tv_sec - start->tv_sec;
        temp.tv_nsec = end->tv_nsec - start->tv_nsec;
    }
    return temp;
}

// A non-scientific calibration routine
void calibrate() {
    struct timespec start, end, sleep = {0};
    calib = 0;

    clock_gettime(CLOCK_MONOTONIC, &start);
    mysleep(&sleep);
    clock_gettime(CLOCK_MONOTONIC, &end);
    struct timespec diff = get_diff(&start, &end);
    calib = (diff.tv_sec * 1000000000 + diff.tv_nsec) / 2;
}

int main() {
    calibrate(); // must be done before using mysleep()

    // use mysleep()
}

Demo

Possible output (with a spike):

calib=157
should be close to 1000:  961
should be close to 1000:  931
should be close to 1000:  906
should be close to 1000:  926
should be close to 1000:  935
should be close to 1000:  930
should be close to 1000:  916
should be close to 1000:  932
should be close to 1000:  124441
should be close to 1000:  911
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda