pthread_cond_timedwait
是 POSIX 线程库中用于条件变量等待的函数,允许线程在等待某个条件时设置超时时间。以下是其概念和示例:
概念
-
作用
线程等待条件变量被触发,但最多等待到指定的超时时间。若超时前条件未被触发,线程自动唤醒并继续执行。 -
参数
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
cond
:要等待的条件变量。mutex
:与条件变量关联的互斥锁,调用前需已加锁。abstime
:绝对超时时间(从 Epoch 开始的秒和纳秒)。
-
返回值
0
:条件变量被触发(可能是正常唤醒或虚假唤醒)。ETIMEDOUT
:超时后未收到信号。- 其他错误码:如互斥锁问题。
-
注意事项
- 必须与互斥锁配合使用。
- 超时时间是绝对时间(如
CLOCK_REALTIME
),需通过系统时间计算。
使用案例
场景:生产者-消费者模型
消费者线程等待任务队列非空,但最多等待 5 秒。若超时则处理其他逻辑。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int task_available = 0; // 模拟任务是否存在void *consumer(void *arg) {struct timespec ts;while (1) {pthread_mutex_lock(&mutex);// 设置超时时间:当前时间 + 5 秒clock_gettime(CLOCK_REALTIME, &ts);ts.tv_sec += 5;// 等待条件变量或超时while (!task_available) {int ret = pthread_cond_timedwait(&cond, &mutex, &ts);if (ret == ETIMEDOUT) {printf("等待超时,处理其他逻辑...\n");pthread_mutex_unlock(&mutex);// 此处可添加超时处理代码return NULL;} else if (ret != 0) {perror("pthread_cond_timedwait");exit(1);}}// 执行任务处理printf("处理任务...\n");task_available = 0; // 重置任务状态pthread_mutex_unlock(&mutex);}return NULL;
}// 生产者线程(示例中未完整实现)
void *producer(void *arg) {// 生产任务并触发条件变量pthread_mutex_lock(&mutex);task_available = 1;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);return NULL;
}int main() {pthread_t tid_consumer, tid_producer;pthread_create(&tid_consumer, NULL, consumer, NULL);// pthread_create(&tid_producer, NULL, producer, NULL);pthread_join(tid_consumer, NULL);// pthread_join(tid_producer, NULL);pthread_cond_destroy(&cond);pthread_mutex_destroy(&mutex);return 0;
}
关键点解释
-
超时时间计算
使用clock_gettime(CLOCK_REALTIME, &ts)
获取当前时间,再增加 5 秒作为绝对超时时间。 -
循环检查条件
即使被唤醒(可能因虚假唤醒),仍需检查条件是否满足(while (!task_available)
)。 -
返回值处理
- 若返回
ETIMEDOUT
,线程主动处理超时逻辑。 - 其他错误需终止或处理异常。
- 若返回
注意事项
- 互斥锁必要性:调用
pthread_cond_timedwait
前必须持有互斥锁,函数内部会释放锁并在返回前重新获取。 - 时间精度:
timespec
使用纳秒级精度,但实际精度依赖系统实现。 - 虚假唤醒:即使未超时或未被唤醒,线程也可能被唤醒,因此条件检查必须放在循环中。
通过合理使用 pthread_cond_timedwait
,可以实现带超时的线程同步,避免永久阻塞。