Using CLOCK_MONOTONIC type in the 'condition variable' wait_for() notify() mechanism
Asked Answered
I

1

6

I am using code that runs on ARM (not Intel processor). Running c++11 code example (CODE A) from: http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/ to test the wait_for() mechanism. This is not working right - looks like the wait_for() does not wait. In Intel works fine. After some research and using pthread library directly and setting MONOTONIC_CLOCK definition, solves the issue (CODE B). (Running on ARM is not the issue)

My problem is : How can I force the C++11 API wait_for() to work with MONOTONIC_CLOCK?

Actually I would like to stay with 'CODE A' but with the support or setting of MONOTONIC_CLOCK. Thanks

CODE A

// condition_variable::wait_for example
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <chrono>             // std::chrono::seconds
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status

std::condition_variable cv;

int value;

void read_value() {
  std::cin >> value;
  cv.notify_one();
}

int main ()
{
  std::cout << "Please, enter an integer (I'll be printing dots): \n";
  std::thread th (read_value);

  std::mutex mtx;
  std::unique_lock<std::mutex> lck(mtx);
  while 
(cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout)        
{
    std::cout << '.' << std::endl;
  }
  std::cout << "You entered: " << value << '\n';

  th.join();

  return 0;
}

CODE B

#include <sys/time.h>
#include <unistd.h> 
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <chrono>             // std::chrono::seconds
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status

const size_t NUMTHREADS = 1;

pthread_mutex_t mutex;
pthread_cond_t cond;

int value;
bool done = false;

void* read_value( void* id )
{
    const int myid = (long)id; // force the pointer to be a 64bit integer
    std::cin >> value;
    done = true;
    printf( "[thread %d] done is now %d. Signalling cond.\n", myid, done 
);
    pthread_cond_signal( &cond ); 

}

int main ()
{

    struct timeval  now;

    pthread_mutexattr_t Attr;
    pthread_mutexattr_init(&Attr);
    pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&mutex, &Attr);

    pthread_condattr_t CaAttr;
    pthread_condattr_init(&CaAttr);
    pthread_condattr_setclock(&CaAttr, CLOCK_MONOTONIC);
    pthread_cond_init(&cond, &CaAttr);

    std::cout << "Please, enter an integer:\n";
    pthread_t threads[NUMTHREADS];
    int t = 0;
    pthread_create( &threads[t], NULL, read_value, (void*)(long)t );

    struct timespec ts;

    pthread_mutex_lock( &mutex );
    int rt = 0;

    while( !done )
    {
        clock_gettime(CLOCK_MONOTONIC, &ts);
        ts.tv_sec += 1;

        rt = pthread_cond_timedwait( & cond, & mutex, &ts );
        std::cout << "..." << std::endl;
    }

    pthread_mutex_unlock( & mutex );
    std::cout << "You entered: " << value << '\n';

    return 0;

}
Interradial answered 23/1, 2019 at 8:47 Comment(1)
@MaximEgorushkin I want cv.wait_for() use MONOTONIC_CLOCK, I am editing my question. thanks.Interradial
C
7

The documentation for std::condition_variable::wait_for says:

A steady clock is used to measure the duration.

std::chrono::steady_clock:

Class std::chrono::steady_clock represents a monotonic clock. The time points of this clock cannot decrease as physical time moves forward.

Unfortunately, this is gcc Bug 41861 (DR887) - (DR 887)(C++0x) does not use monotonic_clock that it uses system_clock instead of steady_clock for condition variables.


One solution is to use wait_until (be sure to read Notes section) function that allows to specify durations relative to a specific clock. E.g.:

cv.wait_until(lck, std::chrono::steady_clock::now() + std::chrono::seconds(1))
Cherie answered 23/1, 2019 at 12:35 Comment(5)
Maxim: As noted in the post I am running on ARM. your suggestion (wait_until) works on Intel but not under ARM. How can check if my c++11 libs are really using MONOTONIC? As noted in 'CODE B' using pure pthreads works under ARMInterradial
@Interradial I would run the application in gdb and step into wait_until to see what happens there.Cherie
The referenced Bug 41861 now is RESOLVED FIXED ("Fixed for GCC 10").Esma
I'm also seeing this on QNX 7.1 with gcc 8.3. The suggestion above though doesn't seem to cure it. Stepping through wait_until in gdb (remote) slows everything down enough to appear to work, but without breakpoints it fails there too (and my target doesn't support tracepoints)Septima
Oh, not a great solution, but boost has this issue fixed. Switching the example code A above to use boost objects makes it work (I tried with 1.74)Septima

© 2022 - 2024 — McMap. All rights reserved.