十二、Linux下线程的同步—条件变量读者与写者问题

一、 案例

写者读者案例,线程对共享资源写,写完成后读者继续读,当读取完成后,在通知写者继续写,依次循环。
在这里插入图片描述
存在以下几种情况:

  • 1 个写者,1 个读者
  • 1 个写者,多个读者
  • 多个写者,多个读者
1. 案例1——一个写者,一个读者。
include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
/***********一个线程写,一个线程读*********************/
//定义两个线程的共有资源
typedef struct
{
        int Res;//需要储存的结果值与计算值

        /*写者的条件变量与互斥锁*/
        pthread_cond_t wr_cond;
        pthread_mutex_t wr_mutex;
        int wr_wait;
                
        /*读者的条件变量与互斥锁*/
        pthread_cond_t rd_cond;
        pthread_mutex_t rd_mutex;
        int rd_wait;
        
}Storage;
/*写入数据*/
void set_data(Storage* s,int value)
{
        s->Res=value;
}
/*读取数据*/
int get_data(Storage* s)
{
        return s->Res;
}
/*
*写数据线程,将计算的结果写入到结果值中再通知读线程
*/
void *set_fn(void* arg)
{
        int i=1;
        int sum=0;
        Storage* s=(Storage*)arg;
        //获取计算一个数据值再传送给读数据线程
        for(i=1;i<=100;i++)
        {
                sum=i+100;
                set_data(s,sum);
                printf("0x%lx(count=%d) write data=%d\n",pthread_self(),i,s->Res);
                //对共享的资源条件变量进行上上锁保护,直到读取线程准备完成                      
                pthread_mutex_lock(&s->rd_mutex);
                while(!s->rd_wait)
                {
                        pthread_mutex_unlock(&s->rd_mutex);
                        usleep(100);
                        pthread_mutex_lock(&s->rd_mutex);
                }
                //读取线程准备好之后,清零,下次继续等待。解锁
                s->rd_wait=0;
                pthread_mutex_unlock(&s->rd_mutex);
                //通知读线程
                pthread_cond_broadcast(&s->rd_cond);

                //写线程完成后,再将写线程上锁阻塞,等待读线程想写线程发送命令
                pthread_mutex_lock(&s->wr_mutex);
                s->wr_wait=1;
                pthread_cond_wait(&s->wr_cond,&s->wr_mutex);
                pthread_mutex_unlock(&s->wr_mutex);

        }
        return 0;
}
/*
*读数据线程,将计算的结果写入到结果值中再通知读线程
*/
void *get_fn(void* arg)
{
        Storage* s=(Storage*)arg;
        int i=1;
        for(i=1;i<=100;i++)
        {
                //对条件变量进行上锁。保护等待队列,直到条件变量触发。
                pthread_mutex_lock(&s->rd_mutex);
                s->rd_wait=1;
                pthread_cond_wait(&s->rd_cond,&s->rd_mutex);
                pthread_mutex_unlock(&s->rd_mutex);
                //获取数据
                get_data(s);
                printf("0x%lx(count=%d )get data=%d\r\n",pthread_self(),i,s->Res);
                //对条件变量进行上锁,直到写线程准备好之后,进行广播通知写线程
                pthread_mutex_lock(&s->wr_mutex);
                while(!s->wr_wait)
                {
                        pthread_mutex_unlock(&s->wr_mutex);
                        usleep(100);
                        pthread_mutex_lock(&s->wr_mutex);
                }
                //写数据的条件清零,以便下次等待写线程等待通知
                s->wr_wait=0;
                pthread_mutex_unlock(&s->wr_mutex);
                pthread_cond_broadcast(&s->wr_cond);
        }
        return 0;
}

//主程序,创建读写任务的函数
int main(void)
{
        int err;
        pthread_t set,get;
        Storage s;
        s.wr_wait=0;
        s.rd_wait=0;
        //初始化条件变量与互斥锁
        pthread_cond_init(&s.wr_cond,NULL);
        pthread_cond_init(&s.rd_cond,NULL);
        pthread_mutex_init(&s.wr_mutex,NULL);
        pthread_mutex_init(&s.rd_mutex,NULL);
        //创建两个线程,一个写数据线程一个对数据线程
        if((err=pthread_create(&set,NULL,set_fn,(void*)&s))!=0)
        {
                perror("set_fn creat fail!\r\n");
        }

        if((err=pthread_create(&get,NULL,get_fn,(void*)&s))!=0)
        {
                perror("get_fn creat fail!\r\n");
        }
        //线程等待
        pthread_join(set,NULL);
        pthread_join(get,NULL);
        //线程互斥锁销毁与条件变量销毁
        pthread_mutex_destroy(&s.wr_mutex);
        pthread_mutex_destroy(&s.rd_mutex);
        pthread_cond_destroy(&s.wr_cond);
        pthread_cond_destroy(&s.rd_cond);

        return 0;
}

运行的结果,一直运行值读取的值为200时,结束运行。
在这里插入图片描述

include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
/***********一个线程写,一个线程读*********************/
//定义两个线程的共有资源
typedef struct
{
        int Res;//需要储存的结果值与计算值

        /*写者的条件变量与互斥锁*/
        pthread_cond_t wr_cond;
        pthread_mutex_t wr_mutex;
        int wr_count;
                
        /*读者的条件变量与互斥锁*/
        pthread_cond_t rd_cond;
        pthread_mutex_t rd_mutex;
        int rd_count;
        
}Storage;
/*写入数据*/
void set_data(Storage* s,int value)
{
        s->Res=value;
}
/*读取数据*/
int get_data(Storage* s)
{
        return s->Res;
}
/*
*写数据线程,将计算的结果写入到结果值中再通知读线程
*/
void *set_fn(void* arg)
{
        int i=1;
        int sum=0;
        Storage* s=(Storage*)arg;
        //获取计算一个数据值再传送给读数据线程
        for(i=1;i<=100;i++)
        {
                sum=i+100;
                set_data(s,sum);
                printf("0x%lx(count=%d) write data=%d\n",pthread_self(),i,s->Res);
                //对共享的资源条件变量进行上上锁保护,直到读取线程准备完成                      
                pthread_mutex_lock(&s->rd_mutex);
                while(s->rd_count<2)
                {		
                        pthread_mutex_unlock(&s->rd_mutex);
                        usleep(100);
                        pthread_mutex_lock(&s->rd_mutex);
                }
                //读取线程准备好之后,清零,下次继续等待。解锁
                s->rd_count=0;
                pthread_mutex_unlock(&s->rd_mutex);
                //通知读线程
                pthread_cond_broadcast(&s->rd_cond);

                //写线程完成后,再将写线程上锁阻塞,等待读线程想写线程发送命令
                pthread_mutex_lock(&s->wr_mutex);
                s->wr_count=1;
                pthread_cond_wait(&s->wr_cond,&s->wr_mutex);
                pthread_mutex_unlock(&s->wr_mutex);

        }
        return 0;
}
/*
*读数据线程,将计算的结果写入到结果值中再通知读线程
*/
void *get_fn(void* arg)
{
        Storage* s=(Storage*)arg;
        int i=1;
        for(i=1;i<=100;i++)
        {
                //对条件变量进行上锁。保护等待队列,直到条件变量触发。
                pthread_mutex_lock(&s->rd_mutex);
                s->rd_count++;
                pthread_cond_wait(&s->rd_cond,&s->rd_mutex);
                pthread_mutex_unlock(&s->rd_mutex);
                //获取数据
                get_data(s);
                printf("0x%lx(count=%d )get data=%d\r\n",pthread_self(),i,s->Res);
                //对条件变量进行上锁,直到写线程准备好之后,进行广播通知写线程
                pthread_mutex_lock(&s->wr_mutex);
                while(!s->wr_count)
                {
                        pthread_mutex_unlock(&s->wr_mutex);
                        usleep(100);
                        pthread_mutex_lock(&s->wr_mutex);
                }
                //s->wr_count=0;第一次这个值直接赋值0,导致第一次可以正常写读,第二次只能写不能读,应该为
                //当第二次做准备时,第一个读线程已经清零0,使得另外的读线程一直处于循环中while(!s->wr_count)
                //写数据的条件清零,以便下次等待写线程等待通知
                s->wr_count++;
				if(s->wr_count==2)
				{
					s->wr_count=0;
				}
                pthread_mutex_unlock(&s->wr_mutex);
                pthread_cond_broadcast(&s->wr_cond);
        }
        return 0;
}

//主程序,创建读写任务的函数
int main(void)
{
        int err;
        pthread_t set,get1,get2;
        Storage s;
        s.wr_count=0;
        s.rd_count=0;
        //初始化条件变量与互斥锁
        pthread_cond_init(&s.wr_cond,NULL);
        pthread_cond_init(&s.rd_cond,NULL);
        pthread_mutex_init(&s.wr_mutex,NULL);
        pthread_mutex_init(&s.rd_mutex,NULL);
        //创建两个线程,一个写数据线程一个对数据线程
        if((err=pthread_create(&set,NULL,set_fn,(void*)&s))!=0)
        {
                perror("set_fn creat fail!\r\n");
        }

        if((err=pthread_create(&get1,NULL,get_fn,(void*)&s))!=0)
        {
                perror("get1_fn creat fail!\r\n");
        }
		if((err=pthread_create(&get2,NULL,get_fn,(void*)&s))!=0)
        {
                perror("get2_fn creat fail!\r\n");
        }
        //线程等待
        pthread_join(set,NULL);
        pthread_join(get1,NULL);
		pthread_join(get2,NULL);
        //线程互斥锁销毁与条件变量销毁
        pthread_mutex_destroy(&s.wr_mutex);
        pthread_mutex_destroy(&s.rd_mutex);
        pthread_cond_destroy(&s.wr_cond);
        pthread_cond_destroy(&s.rd_cond);

        return 0;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值