Main » Programming » Semaphore timing issues in Linux » New reply
    New reply
    Post help

    Presentation

    [b]…[/b] — bold type
    [i]…[/i] — italic
    [u]…[/u] — underlined
    [s]…[/s] — strikethrough
    [code]…[/code] — code block
    [spoiler]…[/spoiler] — spoiler block
    [spoiler=…]…[/spoiler]
    [source]…[/source] — colorcoded block, assuming C#
    [source=…]…[/source] — colorcoded block, specific language[which?]
    [abbr=…]…[/abbr] — abbreviation
    [color=…]…[/color] — set text color
    [jest]…[/jest] — you're kidding
    [sarcasm]…[/sarcasm] — you're not kidding

    Links

    [img]http://…[/img] — insert image
    [url]http://…[/url]
    [url=http://…]…[/url]
    >>… — link to post by ID
    [user=##] — link to user's profile by ID

    Quotations

    [quote]…[/quote] — untitled quote
    [quote=…]…[/quote] — "Posted by …"
    [quote="…" id="…"]…[/quote] — ""Post by …" with link by post ID

    Embeds

    [youtube]…[/youtube] — video ID only please
    Thread review
    wertigon
    Posted by funkyass
    Is all this running on a hard real time os?


    It has soft realtime requirements, yes. Hard realtime no - then we'd use FreeRTOS instead (as we do on a few different products in the same family).
    funkyass Is all this running on a hard real time os?
    wertigon
    Posted by kode54
    Yes, jitter stacks. What, you thought they'd make up for it by returning to you *earlier* the next switch?


    Depends on the loop.

    If you say "sleep 100 ms" at the end of the period, then yes, it will stack.

    If you say "sleep until time x" where x is the time the thread started plus y*100ms, where y is the number of iterations run, then no, it does not stack.

    Unless you tamper with the clock, which you do when running time sync protocols together with this concept. But that is clock changes stacking, not jitter.
    kode54 Yes, jitter stacks. What, you thought they'd make up for it by returning to you *earlier* the next switch?
    wertigon Yes, I am aware of this. It is not a problem that a jitter happens or that it comes in a bit late, as long as it is within the period.

    The problem is that the period gets displaced by x ms every 500 ms, so in absolute numbers and in ideal conditions I would get these numbers:

    100,200,300,400,500
    600,700,800,900,1000
    1100,1200,1300,1400,1500
    1600,1700,1800,1900,2000
    2100,2200,2300,2400,2500

    With a monotonic clock and jitter introduced something like this might be more likely:

    102,205,301,410,541
    601,702,804,903,1002
    1108,1207,1306,1418,1523
    1608,1706,1810,1917,2033
    2119,2202,2301,2412,2507

    Still fine, no deadline misses, might want to do some slight tweaking though. But with REALTIME clock I get these "periods" instead:

    102, 205, 301, 440, 571
    631, 732, 834, 913, 1012
    1118, 1217, 1316, 1388, 1493
    1578, 1676, 1780, 1907, 2023
    2109, 2192, 2291, 2452, 2547


    Which, when compiled into bar charts, provide this kind of periodic accuracy:

    https://imgshare.io/image/timing-problems.t7tqY

    You should never be too early, yet clearly here we are...
    kode54 And you should never expect process yielding to return to your process *EXACTLY* in context switching intervals of the kernel.
    wertigon
    Posted by funkyass
    by not using outdated time syncing software? ntpdate was replaced with ntpd.


    Doesn't matter what time sync software I use, ntpdate was just an example. In theory, I should have a period of 100ms in the above code.

    In practice, if I get timesynced and add/remove +/- 50ms to the realtime clock every 500 ms, I will have timing periods like this (in ms):

    100,100,100,130,100
    100,100,100,80,100
    100,100,100,60,100
    100,100,100,120,100
    100,100,100,150,100

    This is not what I want.
    funkyass by not using outdated time syncing software? ntpdate was replaced with ntpd.
    wertigon Ah, now I understand the problem. Consider the following code:


    struct timespec next_wait;
    clock_gettime(CLOCK_REALTIME, &next_wait);
    int res;

    while (1) {
    next_wait.tv_nsec += 1000000; /* Wait one millisecond */
    next_wait.tv_sec += next_wait.tv_nsec / 1000000000; /* Increase seconds if applicable */
    next_wait.tv_nsec %= 1000000000; /* Reset nsec below 1B nsec */
    if (pthread_mutex_timedlock(&sem, &next_wait) == 0) {
    doSomeStuff();
    pthread_cond_timedwait(&sem, &next_wait);
    }
    }


    Now type this in terminal:

    sudo ntpdate


    Why would this cause period instability, and how can I guarantee period stability? The answer is pretty obvious if you think about it. :)
    funkyass Ok, running UTC eliminates DST, how does NTP screw things up, when you can choose when to run it?
    wertigon Regarding timezones, that is one thing that might screw things up - another one is NTP, or PTP, or a whole slew of different timesync protocols. Not using timesync is unfortunately not an option for this application, we need it.

    Regarding pthread_cond_timedwait, yes, you are correct, after some testing and further research I've confirmed it too.

    So, to sum it up:
    pthread_mutex_timedlock()
    does the same thing as
    sem_timedwait()
    which does a completely different thing from
    pthread_cond_timedwait()


    And both of the former calls support CLOCK_REALTIME and only CLOCK_REALTIME, while only the last call supports CLOCK_MONOTONIC (in addition to CLOCK_REALTIME).

    Why is there no pthread_mutex_timedlock_monotonic()? T_T

    It might be just me, but I strongly suspect this API come from the same guys that developed PHP...
    funkyass if you are worried about DST, use a timezone that doesn't have them, or don't use timezones at all.

    Maybe you should review the ptheads documentation, according to this:
    The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. The application shall ensure that these functions are called with mutex locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust mutexes) or undefined behavior (for other mutexes) results.


    my impression is that pthread_cond_timedwait() unlocks the mutex and then waits.
    wertigon No, I want to take a lock OR wait three seconds, and if the lock is not successfully taken within these three seconds, exit the program with catastrophic failure.

    sem_timedwait() allows me to do this. So does pthread_muted_timedlock().

    But pthread_cond_timedwait() always wait three seconds regardless if the lock is available, or not.

    And cond_timedwait() is the only way I can use CLOCK_MONOTONIC, instead of CLOCK_REALTIME. I wish to avoid CLOCK_REALTIME because it can be altered in this way:


    clock_gettime(CLOCK_REALTIME, &start);
    clock_gettime(CLOCK_REALTIME, &timeout);
    printf("%d HELLO\n",get_seconds_elapsed(timeout,start));
    timeout.tv_sec += 1;
    usleep(timeout);
    clock_gettime(CLOCK_REALTIME, &timeout);
    printf("%d WORLD\n",get_seconds_elapsed(timeout,start));


    The above code should print:


    0 HELLO
    1 WORLD


    Now let us imagine a daylight savings time take place just as the code is run, you instead get


    0 HELLO
    3601 WORLD


    I want this code to be reliable, not prone to the settings of the REALTIME clock changing.
    funkyass Well, first off, why are you writing your own program to sync your clocks?

    Secondly... its smells like a classic race condition: its releasing after 3 seconds cause the child thread got there first. Maybe grab the lock before creating the thread?
    wertigon O.k. so I create a program that spawns a thread, takes a lock, sleep for five and then release. The thread, meanwhile, waits for 1 second before waiting 3 seconds for the lock to disappear.

    This is apparently impossible to do with CLOCK_MONOTONIC, and it frustrates me to no end that I cannot do this, because this means I cannot sync my systems time clock and have a reliable delay (consider: DST, I put a delay on 0.5s, but since DST just changed that delay becomes 3600.5s instead...)

    Here is my code so far, does anyone know how to change this?

    Expected output is that main thread create child thread, takes the lock and waits for 5 seconds before giving it back.

    Meanwhile the child thread should be delayed for 3 seconds if mutex is taken. If you comment out the mutex-taking, it should return after 1s. In both instances it sticks with 3 seconds.


    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>

    pthread_mutex_t lock;
    struct timespec first;
    struct timespec current;

    void timeoutThread(void* args) {
    int err;
    pthread_condattr_t attr;
    pthread_cond_t cond;
    struct timespec timeout;

    clock_gettime(CLOCK_MONOTONIC, &timeout);
    timeout.tv_sec += 3;

    pthread_condattr_init(&attr);
    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
    pthread_cond_init(&cond, &attr);

    usleep(1000000);
    err = pthread_cond_timedwait(&cond, &lock, &time);
    clock_gettime(CLOCK_MONOTONIC, ¤t);
    printf("[%d.%d] ", (int)(current.tv_sec - start.tv_sec), (int)(current.tv_nsec - start.tv_nsec));
    switch(err) {
    case ETIMEDOUT: printf("Timeout expired\n"); break;
    case EINVAL: perror("Error: "); break;
    default: printf("Took it in time\n"); break;
    }
    }

    int main(void) {
    pthread_t handle;

    pthread_mutex_init(&lock, NULL);

    clock_gettime(CLOCK_MONOTONIC, &start);
    clock_gettime(CLOCK_MONOTONIC, ¤t);

    printf("[%d.%d] ", (int)(current.tv_sec - start.tv_sec), (int)(current.tv_nsec - start.tv_nsec));
    printf("Start\n");

    pthread_create(&handle, NULL, (void*)timedThread, NULL);

    pthread_mutex_lock(&lock);
    usleep(5000000);
    pthread_mutex_unlock(&lock);

    clock_gettime(CLOCK_MONOTONIC, ¤t);
    printf("[%d.%d] ", (int)(current.tv_sec - start.tv_sec), (int)(current.tv_nsec - start.tv_nsec));
    printf("Done\n");

    return 0;
    }
      Main » Programming » Semaphore timing issues in Linux » New reply
      Kawa's Github