一:条件变量:
我们知道多线程访问时会出现冲突的问题,为了解决这个问题我们引入互斥锁的概念,即多个线程同时访问理解资源时,获得锁多线程可以完成”读-修改-写”操作,然后释放锁给其他线程.没有获得锁的线程只能挂起等待.
与互斥锁不同,条件变量时挂起等待而不是上锁,条件变量用来自动阻塞一个线程,直到某特殊情况的发生,通常条件变量和互斥锁同时使用.
原理:条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程”条件成立”
条件的检测是在互斥锁的保护条件下进行的,如果一个条件为假,一个线程自动阻塞,并释放等待状态的互斥锁,如果一个线程改变了条件,它发关联的条件变量,唤醒一个或多个等待的线程,重新获得互斥锁,然后重新评价条件.如果梁金成共享读写的内存,条件变量可以实现这两个进程间的线程同步
初始化和释放函数:
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
cond一般用宏来进行初始化.
int pthread_cond_destroy(pthread_cond_t *cond)
返回值:成功返回0,失败返回错误号
和Mutes的初始化和销毁类似,ptread_cond_init函数初始化一个条件变量,attr参数为NULL,则表示缺省属性,ptread_cond_destory函数销毁一个条件变量,如果条件变量是静态的,可以用宏定义初始化,等同于初始化函数,并且attr参数为NULL;
条件变量还有以下函数:
返回值:成功返回0,失败返回错误号
可见,一个条件变量总是和一个Mutex搭配使用,一个线程可以调用pthread_cond_wait在一个条件变量上阻塞等待,这个函数做以下三步操作:
1:释放Mutex
2:阻塞等待
3:当被唤醒时,重新获得Mutex并返回.
pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果达到abstime所指指定的时刻仍然没有别的线程来唤醒当前线程,后返回ETIMEDOUT.一个线程可以调用pthead_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这个Condition Veriable上等待的所有线程.
一个线程可以调用pthread_cond_signal唤醒在某个条件变量上等待的另一个线程,也可以调用
pthread_cond_broadcast唤醒在这个条件变量上等待的所有线程.
生产者消费者问题是同步问题中的一种常见情况,生产者消费者问题 .也称有限缓冲问题,是一个多线程同步问题.在实际运行过程中,生产者的主要作用是生成一定数量的数据放到缓冲区中,然后重复此过程,与此同时,消费者也在缓冲区消耗 这些数据.问题的关键是保证生产者不会在缓冲区满时加入数据,消费者不会在缓冲区空时消耗数据.
二:生产者消费者模型
生产者和生产者之间为互斥关系
消费者和消费者之间为互斥关系
生产者与消费者之间既有同步又有互斥关系
解耦
假设生产者和消费者分别是两个类,如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合),将来如何是消费者代码发生变化,可能会影响生产者,如果都是依赖这个缓冲区,耦合就会相应的降低
支持并发:
生产者直接调用消费者的某个方法,还有另一个弊端.由于函数调用时同步的,在消费者的方法没有返回之前,生产者只好在一边等待,但是如果消费者处理数据很慢,生产者就会浪费很多时间.
使用生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体,(常见的并发类型有进程和线程两种),生产者生产的数据放到缓冲区,就可以继续生产,基本不依赖消费者的处理速度.
支持忙闲不均
换冲区的另外一个好处是,如果生产的数据快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区,等生产者的生产速度降低,消费者再慢慢处理数据.
基于单链表的生产者消费者模型:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
typedef struct SlistNode
{
struct SlistNode*next;
int _data;
}Slist;
//初始化
void Init(Slist*head)
{
if(head!=NULL)
{
head->next =NULL;
head->_data = 0;
}
}
Slist*head =NULL;
//静态创建
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t producter = PTHREAD_COND_INITIALIZER;
//消费者
void* consumer(void *arg)
{
Slist *p = NULL;
while(1)
{
pthread_mutex_lock(&lock);//加锁
while(head ==NULL)
{
//条件不满足,阻塞式等待
pthread_cond_wait(&producter,&lock);
}
//尾删
p = head;
head =head->next;
p->next = NULL;
pthread_mutex_unlock(&lock);//释放锁
printf("Consumer success :_data is %d\n",p->_data);
free(p);
p = NULL;
}
return NULL;
}
//生产者
void *product(void *arg)
{
while(1)
{
sleep(rand()%2);
Slist*p = malloc(sizeof(Slist));
pthread_mutex_lock(&lock);
Init(p);
p->_data = rand()%1000;
//头插
p->next = head;
head= p;
pthread_mutex_unlock(&lock);
printf("call consumer,product success,data is:%d\n",p->_data);
pthread_cond_signal(&producter);
}
}
int main()
{
pthread_t t_product;
pthread_t t_consumer;
pthread_create(&t_product,NULL,product,NULL);//创建线程
pthread_create(&t_consumer,NULL,consumer,NULL);//创建线程
pthread_join(t_product,NULL);//线程等待
pthread_join(t_consumer,NULL);
return 0;
}