Ciph3rzer0
Ciph3rzer0

Reputation: 577

pthread_cond_timedwait()

void wait(int timeInMs)
{
    struct timespec timeToWait;
    timeToWait.tv_sec = 5;
    timeToWait.tv_nsec = timeInMs*1000;

    int rt;

    pthread_mutex_lock(&fakeMutex);
    rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
    pthread_mutex_unlock(&fakeMutex);
}

I'm using this code to try to get a thread to wait around for a bit, but it doesn't work at all. No errors, it just doesn't make the program execute any slower.

I was thinking maybe each thread needs to have it's own condition and mutex, but that really doesn't make sense to me.

Upvotes: 7

Views: 72753

Answers (7)

user1709180
user1709180

Reputation: 121

pthread_cond_timedwait uses absolute time, so need to:

  • use gettimeofday to retrieve current time.
  • timespec.tv_nsec is nanosecond, it can't be large than 1 second.
  • timeval.tv_usec is microsecond (1000 nanoseconds).
  • timeInMs is millisecond: 1 millisecond = 1000 microseconds = 1000 * 1000 nanoseconds.

    void wait(int timeInMs)
    {
        struct timeval tv;
        struct timespec ts;
    
        gettimeofday(&tv, NULL);
        ts.tv_sec = time(NULL) + timeInMs / 1000;
        ts.tv_nsec = tv.tv_usec * 1000 + 1000 * 1000 * (timeInMs % 1000);
        ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
        ts.tv_nsec %= (1000 * 1000 * 1000);
    
        int n = pthread_cond_timedwait(&condition, &mutex, &ts);
        if (n == 0)
            // TODO: singaled
        else if (n == ETIMEDOUT)
            // TODO: Time out.
    }
    

Upvotes: 10

Alex
Alex

Reputation: 226

Main reference: http://pubs.opengroup.org/onlinepubs/009695299/functions/pthread_cond_timedwait.html

FIX of the code of andrewrk above

I can confirm Adrian May that gettimeofday doesn't function correctly! The code behavior of andrewrk inside an infinite thread like this

static void * thread_infinite(void * unused) {
while (1) {
        // compute stuff
        mywait(5);
}

is unpredictable: it runs approximate 700 times more until it blocks!

The correct version of the code of andrewrk is:

pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;

void mywait(int timeInS)
{
    struct timespec ts;
    struct timeval now;
    int rt = 0;

//    gettimeofday(&now,NULL); // DOES NOT FUNCTION CORRECTLY
//    timeToWait.tv_sec = now.tv_sec+5;
//    timeToWait.tv_nsec = (now.tv_usec+1000UL*timeInMs)*1000UL;

    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += timeInS;

    pthread_mutex_lock(&fakeMutex);

    do {
        rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &ts);
        }
    while (rt == 0);

    pthread_mutex_unlock(&fakeMutex);
}

Upvotes: 4

Furquan
Furquan

Reputation: 678

Using any variant of sleep, the behavior is not guaranteed. All the threads can also sleep since the kernel is not aware of the different threads.

A safer and cleaner solution to use is pthread_cond_timedwait. You used the API incorrectly. Here is a better example:

pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;

void mywait(int timeInMs)
{
    struct timespec timeToWait;
    struct timeval now;
    int rt;

    gettimeofday(&now,NULL);


    timeToWait.tv_sec = now.tv_sec+5;
    timeToWait.tv_nsec = (now.tv_usec+1000UL*timeInMs)*1000UL;

    pthread_mutex_lock(&fakeMutex);
    rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
    pthread_mutex_unlock(&fakeMutex);
    printf("\nDone\n");
}

void* fun(void* arg)
{
    printf("\nIn thread\n");
    mywait(1000);
}

int main()
{
    pthread_t thread;
    void *ret;

    pthread_create(&thread, NULL, fun, NULL);
    pthread_join(thread,&ret);
}

You need to specify how much time to wait from current time. Since you were only telling 5 sec and some nano-seconds it found that the time had already passed and did not wait...Please let me know if any more doubts.

Upvotes: 19

wrapperm
wrapperm

Reputation: 1296

Here is an example where I have created a thread from main loop which does a scan of a directory and have a timeout of 5 sec. And signalling from the thread happens using a conditional variable which is a global. We keep checking for this signal from thread:

    pthread_cond_t C_KISU_SwagntUtilityBase::m_cond; /*Global variable*/
/*Inside main function*/    
/*Local variables*/
          pthread_condattr_t l_attr;
          pthread_condattr_init(&l_attr);
          pthread_condattr_setclock(&l_attr, CLOCK_MONOTONIC);
          pthread_cond_init(&C_KISU_SwagntUtilityBase::m_cond, &l_attr);

          Int32 l_threadid = pthread_create(&l_updatethread,NULL,C_KISU_SwagntUtilityBase::ThreadScanDirectoryByFilter,&l_filer);
          if(CMP_ZERO == l_threadid)
          {
            pthread_mutex_t l_mutex = PTHREAD_MUTEX_INITIALIZER;
            struct timespec l_ts;
            if (clock_gettime(CLOCK_MONOTONIC, &l_ts) == INIT_NEGONE)
            {
             /* Handle error */
            }
            printf("\n Setting max time to  run ThreadScanDirectoryByFilter as 5 second"));
            l_ts.tv_sec += l_filer.m_max_scan_time;

            if(l_filer.m_scan_status == 0)
            {
              pthread_mutex_lock(&l_mutex);
              int l_rt = pthread_cond_timedwait(&C_KISU_SwagntUtilityBase::m_cond, &l_mutex, &l_ts);
              if (ETIMEDOUT == l_rt)
              {
                printf("\n timeout has happened before scan routine could finish"));
              }
              else if (EOK  == l_rt)
              {
                printf("\n Scan successful"));
              }
              else
              {
                printf("\n Unknown error while timeout condition check"));
              }
              pthread_mutex_unlock(&l_mutex);
            }
          }
          else
          {
            printf("\n Error while creating thread\n");

          }

Upvotes: 1

David Schwartz
David Schwartz

Reputation: 182753

The pthread_cond_timedwait function takes an absolute time, not a relative time. It takes the time you want to stop waiting, not how long you want to wait.

Upvotes: 22

Tom
Tom

Reputation: 31

Considering you are using timespec, and your goal isn't to synchronize but to wait I'd suggest nanosleep.

#include <time.h>

.
.
.

  struct timespec remain;
  remain.tv_sec = 5;
  remain.tv_nsec = timeInMs * 1000;

  do {
    if ( nanosleep( &remain, &remain ) == 0 || errno != EINTR ) {
      break;
    }
  } while ( 1 );

.
.
.

Upvotes: 3

Arkaitz Jimenez
Arkaitz Jimenez

Reputation: 23168

That code doesn't sleep, it checks a condition for a while. As you are not probably setting cond ok it just returns immediately.

If you are not willing to synchronize threads around a signal then pthread_cond _wait is not what you need. Check here how condition variables work.

if you want to sleep with seconds precision use sleep

If you want to sleep with microseconds precision use select with timevals.

Upvotes: 2

Related Questions