最近在做一个项目,需要实现两个线程之间的等待超时机制。例如A线程等待B线程,需要实现等待超时机制。解决方案是利用条件变量实现。
1. 条件变量
条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线承间的同步。
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t * mutex, const struct timespec *abstime);
其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。结构pthread_condattr_t是条件变量的属性结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可用,默认值是PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。注意初始化条件变量只有未被使用时才能重新初始化或被释放。
(1). pthread_cond_wait() : 使线程阻塞在一个条件变量上。线程解开mutex指向的锁并被条件变量cond阻塞。线程可以被函数pthread_cond_signal和函数pthread_cond_broadcast唤醒,但是要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。
(2). pthread_cond_timedwait(): 它比函数pthread_cond_wait() 多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。
(3). pthread_cond_signal(): 它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是,必须用保护条件变量的互斥锁来保护这个函数,否则条件满足信号又可能在测试条件和调用pthread_cond_wait函数之间被发出,从而造成无限制的等待。
2. 代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>
void root()
{
........
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
/**
* Create a new thread to call root() and wait it completed.
*/
void start_root_and_timedwait()
{
pthread_t tid;
if (pthread_create(&tid, NULL, (void *)root, NULL) != 0) {
LOGE("############## Error: pthread_create failed ##############");
} else {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
struct timeval now;
struct timespec abstime;
gettimeofday(&now, NULL);
abstime.tv_sec = now.tv_sec + 60;//timeout = 60 seconds
abstime.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(&mutex);
pthread_cond_timedwait(&cond, &mutex, &abstime);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
}
注意:第一个参数&tid 不能设为NULL,否则创建thread 时进程会崩溃。
pthread_create(&tid, NULL, (void *)root, NULL)