头文件:#include <pthread.h>
与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁!
条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量的两个动作:
条件不满, 阻塞线程
当条件满足, 通知阻塞的线程开始工作
pthread_cond_init
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
功能:
初始化一个条件变量
参数:
cond:指向要初始化的条件变量指针。
attr:条件变量属性,通常为默认值,传NULL即可
也可以使用静态初始化的方法,初始化条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:
成功:0
失败:非0错误号
pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *cond);
功能:
销毁一个条件变量
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号
pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
功能:
阻塞等待一个条件变量
a) 阻塞等待条件变量cond(参1)满足
b) 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
a) b) 两步为一个原子操作。
c) 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);
参数:
cond:指向要初始化的条件变量指针
mutex:互斥锁
返回值:
成功:0
失败:非0错误号
pthread_cond_timedwait
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
功能:
限时等待一个条件变量
参数:
cond:指向要初始化的条件变量指针
mutex:互斥锁
abstime:绝对时间
返回值:
成功:0
失败:非0错误号
abstime说明:
struct timespec {
time_t tv_sec; /* seconds / // 秒
long tv_nsec; / nanosecondes*/ // 纳秒
}
time_t cur = time(NULL); //获取当前时间。
struct timespec t; //定义timespec 结构体变量t
t.tv_sec = cur + 1; // 定时1秒
pthread_cond_timedwait(&cond, &t);
pthread_cond_signal
int pthread_cond_signal(pthread_cond_t *cond);
功能:
唤醒至少一个阻塞在条件变量上的线程
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号
pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:
唤醒全部阻塞在条件变量上的线程
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号
生产者消费者程序
typedef struct node
{
int data;
struct node* next;
}Node;
Node* head = NULL;
pthread_mutex_t mutex;
pthread_cond_t cond;
void* producer(void* arg)
{
while (1)
{
Node* pnew = (Node*)malloc(sizeof(Node));
pnew->data = rand() % 1000; // 0-999
pthread_mutex_lock(&mutex);
pnew->next = head;
head = pnew;
printf("====== produce: %lu, %d\n", pthread_self(), pnew->data);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
sleep(rand() % 3);
}
return NULL;
}
void* customer(void* arg)
{
while (1)
{
pthread_mutex_lock(&mutex);
if (head == NULL)
{
// 该函数会对互斥锁解锁
pthread_cond_wait(&cond, &mutex);
// 解除阻塞之后,对互斥锁做加锁操作
}
// 链表不为空 - 删除头结点
Node* pdel = head;
head = head->next;
printf("------ customer: %lu, %d\n", pthread_self(), pdel->data);
free(pdel);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(int argc, const char* argv[])
{
pthread_t p1, p2;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&p1, NULL, producer, NULL);
pthread_create(&p2, NULL, customer, NULL);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
##条件变量的优缺点
相较于mutex而言,条件变量可以减少竞争。
如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果链表中没有数据,消费者之间竞争互斥锁是无意义的。
有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。
网友评论