pthread_cond_timedwait函数使用

1 函数原型

#include <pthread.h>

int pthread_cond_timedwait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex,
           const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex);

2 注意事项

pthread_cond_timedwait()用于等待一个条件变量,等待条件变量的同时可以设置等待超时。这是一个非常有用的功能,如果不想一直等待某一条件变量,就可以使用这个函数。

2.1 abstime参数

这里面的超时时间是一个绝对值,也就是距离1970-1-1 日的时间值,而不是一个时间段。比如说当前时间为2021-5-15 17:14:00.100,我们想通过这个函数设置最大超时为2500ms,那么就需要设置abstime时间为2021-5-15 17:14:02.600.

2.2 时间获取

条件变量默认使用的时间是CLOCK_REALTIME。通过clock_gettime()接口获取时间。
 

static long long tm_to_ns(struct timespec tm)
{
	return tm.tv_sec * 1000000000 + tm.tv_nsec;
}

static struct timespec ns_to_tm(long long ns)
{
	struct timespec tm;
	tm.tv_sec = ns / 1000000000;
	tm.tv_nsec = ns - (tm.tv_sec * 1000000000);
	return tm;
}

  
{ 

        示意代码:

	struct timespec start_tm;
	struct timespec end_tm;
        int timeout_ms = 2500;
	
	clock_gettime(CLOCK_REALTIME, &start_tm);
	end_tm = ns_to_tm(tm_to_ns(start_tm) + timeout_ms*1000000);

	pthread_mutex_lock(&mtx);
	
	while (等待的条件) {
		if (pthread_cond_timedwait(&cond, &mtx, &end_tm) == ETIMEDOUT) {
			/*
			 * 如果超时则退出等待
			 */
			ret = -1;
			break;
		}
	}


}

但是CLOCK_REALTIME时间容易产生变化,比如通过NTP校准系统时钟,那么系统时钟会产生跨度变化。所以一般我们需要使用CLOCK_MONOTONIC。

但是条件变量默认使用的时钟是CLOCK_REALTIME,所以需要通过条件变量的属性来设置条件变量使用的时钟。

    pthread_condattr_t attr;
    pthread_condattr_init(&attr);
	
#if 0
	clockid_t clock_id;
	pthread_condattr_getclock(&attr, &clock_id);
	printf("clock_id: %d\n", clock_id);
#endif

    /*
     * pthread_cond_timedwait()默认使用的是CLOCK_REALTIME,
     * CLOCK_REALTIME容易受系统影响,比如校时操作
     * 所以条件变量使用的时钟改为CLOCK_MONOTONIC
     * 参考:https://man7.org/linux/man-pages/man3/pthread_cond_timedwait.3p.html
     */
    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);

    pthread_cond_init(&cond, &attr);
	
    pthread_condattr_destroy(&attr);





static long long tm_to_ns(struct timespec tm)
{
	return tm.tv_sec * 1000000000 + tm.tv_nsec;
}

static struct timespec ns_to_tm(long long ns)
{
	struct timespec tm;
	tm.tv_sec = ns / 1000000000;
	tm.tv_nsec = ns - (tm.tv_sec * 1000000000);
	return tm;
}

  
{ 

        示意代码:

	struct timespec start_tm;
	struct timespec end_tm;
        int timeout_ms = 2500;
	
	clock_gettime(CLOCK_MONOTONIC, &start_tm);
	end_tm = ns_to_tm(tm_to_ns(start_tm) + timeout_ms*1000000);

	pthread_mutex_lock(&mtx);
	
	while (等待的条件) {
		if (pthread_cond_timedwait(&cond, &mtx, &end_tm) == ETIMEDOUT) {
			/*
			 * 如果超时则退出等待
			 */
			ret = -1;
			break;
		}
	}


}

如果想看完整的使用历程可以参考:

Linux应用编程实现简单队列功能_霍宏鹏的博客-CSDN博客

3 描述

pthread_cond_timedwait(3p) - Linux manual page

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.

       These functions atomically release mutex and cause the calling
       thread to block on the condition variable cond; atomically here
       means ``atomically with respect to access by another thread to
       the mutex and then the condition variable''. That is, if another
       thread is able to acquire the mutex after the about-to-block
       thread has released it, then a subsequent call to
       pthread_cond_broadcast() or pthread_cond_signal() in that thread
       shall behave as if it were issued after the about-to-block thread
       has blocked.

       Upon successful return, the mutex shall have been locked and
       shall be owned by the calling thread. If mutex is a robust mutex
       where an owner terminated while holding the lock and the state is
       recoverable, the mutex shall be acquired even though the function
       returns an error code.

       When using condition variables there is always a Boolean
       predicate involving shared variables associated with each
       condition wait that is true if the thread should proceed.
       Spurious wakeups from the pthread_cond_timedwait() or
       pthread_cond_wait() functions may occur. Since the return from
       pthread_cond_timedwait() or pthread_cond_wait() does not imply
       anything about the value of this predicate, the predicate should
       be re-evaluated upon such return.

       When a thread waits on a condition variable, having specified a
       particular mutex to either the pthread_cond_timedwait() or the
       pthread_cond_wait() operation, a dynamic binding is formed
       between that mutex and condition variable that remains in effect
       as long as at least one thread is blocked on the condition
       variable. During this time, the effect of an attempt by any
       thread to wait on that condition variable using a different mutex
       is undefined. Once all waiting threads have been unblocked (as by
       the pthread_cond_broadcast() operation), the next wait operation
       on that condition variable shall form a new dynamic binding with
       the mutex specified by that wait operation. Even though the
       dynamic binding between condition variable and mutex may be
       removed or replaced between the time a thread is unblocked from a
       wait on the condition variable and the time that it returns to
       the caller or begins cancellation cleanup, the unblocked thread
       shall always re-acquire the mutex specified in the condition wait
       operation call from which it is returning.

       A condition wait (whether timed or not) is a cancellation point.
       When the cancelability type of a thread is set to
       PTHREAD_CANCEL_DEFERRED, a side-effect of acting upon a
       cancellation request while in a condition wait is that the mutex
       is (in effect) re-acquired before calling the first cancellation
       cleanup handler. The effect is as if the thread were unblocked,
       allowed to execute up to the point of returning from the call to
       pthread_cond_timedwait() or pthread_cond_wait(), but at that
       point notices the cancellation request and instead of returning
       to the caller of pthread_cond_timedwait() or pthread_cond_wait(),
       starts the thread cancellation activities, which includes calling
       cancellation cleanup handlers.

       A thread that has been unblocked because it has been canceled
       while blocked in a call to pthread_cond_timedwait() or
       pthread_cond_wait() shall not consume any condition signal that
       may be directed concurrently at the condition variable if there
       are other threads blocked on the condition variable.

       The pthread_cond_timedwait() function shall be equivalent to
       pthread_cond_wait(), except that an error is returned if the
       absolute time specified by abstime passes (that is, system time
       equals or exceeds abstime) before the condition cond is signaled
       or broadcasted, or if the absolute time specified by abstime has
       already been passed at the time of the call. When such timeouts
       occur, pthread_cond_timedwait() shall nonetheless release and re-
       acquire the mutex referenced by mutex, and may consume a
       condition signal directed concurrently at the condition variable.

       The condition variable shall have a clock attribute which
       specifies the clock that shall be used to measure the time
       specified by the abstime argument. The pthread_cond_timedwait()
       function is also a cancellation point.

       If a signal is delivered to a thread waiting for a condition
       variable, upon return from the signal handler the thread resumes
       waiting for the condition variable as if it was not interrupted,
       or it shall return zero due to spurious wakeup.

       The behavior is undefined if the value specified by the cond or
       mutex argument to these functions does not refer to an
       initialized condition variable or an initialized mutex object,
       respectively.

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值