5

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;

}
progtec
  • 61
  • 1
  • 4

1 Answers1

6

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))
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 2
    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 ARM – progtec Jan 23 '19 at 15:35
  • @progtec I would run the application in gdb and step into `wait_until` to see what happens there. – Maxim Egorushkin Jan 23 '19 at 16:18
  • 2
    The referenced [Bug 41861](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861) now is `RESOLVED FIXED` ("Fixed for GCC 10"). – phinz Sep 10 '20 at 07:06
  • 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) – Matt Feb 22 '22 at 20:20
  • 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) – Matt Feb 23 '22 at 14:05