条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
linux定义一系列函数来操作条件变量,如下:
初始化和反初始化函数:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr); //初始化条件变量
int pthread_cond_destroy(pthread_cond_t *cond); //销毁条件变量
返回值:若成功,返回0;若出错,返回错误编号
参数:
- cond:指向结构pthread_cond_t的指针
- attr:为NULL时, 会创建一个默认属性的条件变量
初始化条件变量有两种方式,一种是静态,另一种是动态
静态态初始化:pthread_cond_t cond = PTHREAD_COND_INITIALIER;
动态初始化:int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
等待函数:
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restric mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);
返回值:若成功,返回0;若出错,返回错误编号
pthread_cond_wait是阻塞等待
pthread_cond_timedwait是阻塞超时等待.
通知函数:
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
返回值:若成功,返回0;若出错,返回错误编号
这两个函数相当于发送信号通知等待的条件满足了。pthread_cond_signal用于解除单个线程的阻塞,相当于单播。pthread_cond_broadcast用于解除所有线程的阻塞,相当于多播。
示例程序:
/* cond_mutex.c*/
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
static int count = 0 ;
#define FILENAME "cond_mutex_save"
/*线程一*/
void thread1(void * arg)
{
char write_buf[] = "1";
int fd = *(int *)arg;
printf("this is pthread1,fd = %d\n",fd);
int i = 0;
while(1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
for(i = 0;i<5;i++)
{
if (write(fd,write_buf,sizeof(write_buf)))
{
perror("write");
}
count++;
}
printf("This is a pthread1....and count = %d\n",count);
/*信号量加一,V 操作*/
pthread_mutex_unlock(&mutex);
}
}
/*线程二*/
void thread2(void * arg)
{
char write_buf[] = "2";
int fd = *(int *)arg;
printf("this is pthread2 and fd = %d\n",fd);
int i = 0;
while(1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
for(i = 0;i<5;i++)
{
if (write(fd,write_buf,sizeof(write_buf)))
{
perror("write");
}
count++;
}
printf("This is a pthread2.... count = %d\n",count);
pthread_mutex_unlock(&mutex);
}
}
int main(void)
{
int fd = open(FILENAME,O_RDWR | O_CREAT,0777);
if(fd < 0)
{
perror("open");
}
printf("open success!\n");
int i,ret;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_t id1,id2;
/*创建线程一*/
ret=pthread_create(&id1,NULL,(void *) thread1,&fd);
if(ret!=0){
perror("Create pthread error!\n");
}
/*创建线程二*/
ret=pthread_create(&id2,NULL,(void *) thread2,&fd);
if(ret!=0){
perror ("Create pthread error!\n");
}
while(1)
{
sleep(1);
pthread_cond_signal(&cond);
}
/*等待线程结束*/
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 0;
}
实验结果:
ubuntu:~/test/pthread_test$ gcc cond_mutex.c -o cond_mutex -lpthread
ubuntu:~/test/pthread_test$ ./cond_mutex
open success!
this is pthread1,fd = 3
this is pthread2 and fd = 3
write: Success
write: Success
write: Success
write: Success
write: Success
This is a pthread1....and count = 5
write: Success
write: Success
write: Success
write: Success
write: Success
This is a pthread2.... count = 10
write: Success
write: Success
write: Success
write: Success
write: Success
This is a pthread1....and count = 15
write: Success
write: Success
write: Success
write: Success
write: Success
This is a pthread2.... count = 20
write: Success
write: Success
write: Success
write: Success
write: Success
从上面的例子程序中,可以看到,我们在main函数中创建线程一和线程二。然后调用函数pthread_mutex_init(&mutex, NULL)、pthread_cond_init(&cond, NULL) 初始化互斥锁mutex 和条件变量cond。 接着每隔1秒调用函数pthread_cond_signal(&cond) 给线程发送条件变量cond满足的信号。在线程一和线程二,每次向文件 cond_mutex_save 写入数据之前,都会调用pthread_cond_wait(&cond, &mutex) 函数判断条件变量是否满足。如果不满足条件,则继续等待。而且在访问文件之前调用pthread_mutex_lock(&mutex) 函数给资源加上互斥锁,让线程一和线程二访问文件的时候互斥。