leeknives 2017-10-14
条件变量是实现线程间同步的一种方法,条件变量用来自动阻塞一个线程,直到收到收到一个cond信号或其它特殊情况发送,条件变量使用的时候必须与互斥量同时使用,这是为了保证条件量在线程间操作的“原子性”。
1、创建一个条件变量cond:
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
在初始化一个条件变量时如果attr为 NULL,测使用默认值初始化一个条件变量cond,相当于下面的方式定义一个条件变量cond;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
2、销毁一个条件变量cond:
int pthread_cond_destroy(pthread_cond_t *cond);
可以销毁一个条件变量cond,使其未初始化。一个被引用的条件变量是不可被销毁的,使用一个被销毁的条件变量将造成为止的后果,在默认条件下测试,将导致线程将直处于阻塞状态。
3、等待一个条件变量:
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
将导致线程阻塞在条件变量cond,应用程序应确保被mutex锁定的线程调用这些函数,否则可能导致未知错误。
这两个函数在执行开始将自动释放mutex,等待条件变量之后将自动锁定mutex,如果有其它线程正在调用mutex将导致线程阻塞。具体执行过程如下所示:
pthread_mutex_cond_unlock(mutex);
pthread_cond_wait(cond);
pthread_mutex_cond_lock(mutex);
在包含pthread_cond_wait函数的线程结束前一定要释放mutex,否则可能会造成其它等待cond的线程一直阻塞。如果有其它线程获得了互斥锁mutex,也将导致cond的线程阻塞。
4、唤醒一个被cond阻塞的线程:
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal将唤醒一个被阻塞的线程,pthread_cond_broadcast是唤醒所有被阻塞的线程,如果没有被阻塞的线程pthread_cond_signal与pthread_cond_broadcast也将正确返回,但是其产生的信号将不起任何作用。
5、使用pthread_cond_timedwait实现精确延时,在单个线程中的cond与mutex可以直接用下面方式实现精确延时:
void set_abswaittime(struct timespec*outtime, int ms)
{
long sec ;
long usec ;
struct timeval tnow;
gettimeofday(&tnow, NULL);
usec = tnow.tv_usec + ms*1000;
sec = tnow.tv_sec+usec/1000000;
outtime->tv_nsec=(usec%1000000)*1000;
outtime->tv_sec=sec;
}
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
struct timespec abstime;
set_abswaittime(&abstime,1000);
pthread_cond_wait(&tcond, &tmutex, &abstime);
6、条件变量使用测试,测试代码如下:
//
// 创建人: levy
// 创建时间:May 25, 2017
// 功能:main.c
// Copyright (c) 2016 levy. All Rights Reserved.
// Ver 变更日期 负责人 变更内容
// ──────────────────────────────────────────────────────────────────────────
// V0.01 May 25, 2017 levy 初版
//
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
pthread_mutex_t test_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t test_cond=PTHREAD_COND_INITIALIZER;
int test_count;
void * test_thread1(void *arp)
{
int s=(int)arp;
printf("I am thread %ld ,I will sleep %d s .\n",pthread_self(),s);
sleep(s);
pthread_mutex_lock(&test_mutex);
pthread_cond_wait(&test_cond,&test_mutex);
test_count++;
printf("my thread id is %ld ,testcount=%d \n",pthread_self(),test_count);
pthread_mutex_unlock(&test_mutex);
pthread_exit(NULL);
}
int main(void )
{
pthread_t th[3];
test_count=0;
for(int i=0;i<3;i++)
{
pthread_create(&th[i],NULL,test_thread1,i);
}
for(int i=0;i<3;i++)
{
sleep(3);
pthread_cond_signal(&test_cond);
}
for(int i=0;i<3;i++)
{
pthread_join(th[i],NULL);
}
pthread_exit(NULL);
}
输出结果:
I am thread 140391800571648 ,I will sleep 1 s .
I am thread 140391808964352 ,I will sleep 1 s .
I am thread 140391792178944 ,I will sleep 1 s .
my thread id is 140391808964352 ,testcount=1
my thread id is 140391800571648 ,testcount=2
my thread id is 140391792178944 ,testcount=3