版权声明:允许转载,请注明文章出处 https://blog.csdn.net/Vickers_xiaowei/article/details/86406133
条件变量
需要一个条件:表示临界区有没有资源
为什么条件变量要和互斥锁搭配使用?
因为等待需要被唤醒,而被唤醒的前提条件就是条件已经满足,并且这个条件本身就是一个临界资源,因此改变条件的操作需要被保护。
条件变量的初始化及销毁:
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
没有资源就去阻塞等待:
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);
pthread_cond_wait函数会对互斥锁做判断,如果调用线程加锁,就解锁,然后陷入等待,整个过程是原子操作,防止消费者先拿到锁,发现条件变量不满足,无法消费,它陷入阻塞等待,这时候生产者得不到锁。
唤醒在条件变量上的线程:
int pthread_cond_broadcast(pthread_cond_t *cond);//广播唤醒
int pthread_cond_signal(pthread_cond_t *cond);//唤醒第一个等待的条件变量的线程
条件变量代码演示:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
int basket = 0;//公共条件,需要互斥锁来保证原子性
void* saler(void*arg)
{
while(1){
pthread_mutex_lock(mutex);
if(basket == 0){
printf("I sell a good\n");
basket = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(mutex);
}
}
return NULL;
}
void* customer(void*arg)
{
while(1){
pthread_mutex_lock(mutex);
if(basket == 0){
//初始状态等待,睡眠
//pthread_cond_wait函数会对互斥锁做判断,如果调用线程加锁,就解锁,然后陷入等待,整个过程是原子操作
pthread_cond_wait(&cond,&mutex);
}
printf("I bought a gift for my girl friend!!\n");
basket = 0;
pthread_mutex_unlock(mutex);
}
return NULL;
}
int main()
{
pthread_t t1,t2;
int ret;
pthread_cond_init(&cond,NULL);//条件变量初始化
pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&t1,NULL,saler,NULL);
if(ret != 0){
perror("pthread_create error");
exit(-1);
}
ret = pthread_create(&t1,NULL,customer,NULL);
if(ret != 0){
perror("pthread_create error");
exit(-1);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
Posix信号量
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源的目的。 但POSIX可以用于线程间同步。systemV标准posix实现进程间通信
即可以实现同步也可以实现互斥,既可以用于进程间同步与互斥,也可以用于线程间的同步与互斥。
信号量是什么(具有一个等待队列的计数器)
posix线程同步实现
消费者:没有资源则等待
生产者:生产出来则通知队列中的等待者
1、信号量的初始化
int sem_init(sem_t *sem, int pshared, unsigned int value);
- If pshared has the value 0, then the semaphore is shared between the threads of a process
If pshared is nonzero, then the semaphore is shared between processes
sem:信号量变量名
value:信号量初始计数
成功:0 失败:-1
2、信号量的操作(等待/通知)
等待:对于消费者,没有资源则等待。等待信号量,会将信号量的值减1。
int sem_wait(sem_t *sem);//阻塞等待
int sem_trywait(sem_t *sem);//没有资源,报错返回
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);//限时等待,超时报错返回
发布信号量:生产者生产出资源,通知消费者。发布信号量,表示资源使⽤完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);
3、信号量的释放
int sem_destroy(sem_t *sem);
Link with -pthread.
/*信号量实现线程同步与互斥
* 同步:
* 1、信号量的初始化
* 2、信号量的操作(等待/通知)
* 3、信号量的释放
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;//定义信号量
void*thr_producer(void*arg)
{
while(1){
sleep(1);
printf("I make a hot beef noodles!!\n");
sem_post(&sem);
}
return NULL;
}
void*thr_customer(void*arg)
{
while(1){
sem_wait(&sem);
printf("It is declicious!!\n");
}
return NULL;
}
int main()
{
pthread_t t1,t2;
int ret;
sem_init(&sem,0,0);//信号量初始化
ret = pthread_create(&t1,NULL,thr_producer,NULL);
if(ret != 0 ){
perror("pthread_create error");
exit(-1);
}
ret = pthread_create(&t2,NULL,thr_customer,NULL);
if(ret != 0 ){
perror("pthread_create error");
exit(-1);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
sem_destroy(&sem);
return 0;
}
posix线程互斥实现
信号量的操作(等待+通知)
sem_wait()信号量减1
sem_post()发布信号量,表示资源使⽤完毕,可以归还资源了。将信号量值加1。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;//定义信号量
int ticket = 100;//黄牛抢票,总票数100
void* buy_ticket(void*arg)
{
int id = (int)arg;
while(1){
sem_wait(&sem);
if(ticket > 0){
usleep(1000);
ticket--;
printf("%d Buy a ticket,the ticket has %d\n",id,ticket);
}
sem_post(&sem);
}
return NULL;
}
int main()
{
pthread_t tid[4];
int ret;
sem_init(&sem,0,1);//信号量初始化
int i = 0;
for(i=0;i<4;i++){
ret = pthread_create(&tid[i],NULL,buy_ticket,(void*)i);
if(ret != 0 ){
perror("pthread_create error");
exit(-1);
}
}
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
pthread_join(tid[2],NULL);
pthread_join(tid[3],NULL);
sem_destroy(&sem);
return 0;
}
信号量与条件变量在保证同步时候的区别:信号量是修改自己内部的资源计数,这个内部的资源计数就是条件,而条件变量修改的是外部的条件,需要我们用户来修改
STL自身不能保证原子性
信号量的操作是一个原子操作。