消费者生产者问题---线程互斥锁+条件变量

想实现线程的同步,解决消费者问题,利用互斥锁,发现不能成功,也许还要加其他的只是,

#include <stdio.h>
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
typedef struct
{
    int product[5];
    int count;
}
PRODUCT;
PRODUCT buffer;//缓冲区结构,消费者和生产者共同操作
pthread_mutex_t mutex;//创建互斥锁
pthread_t tid;//新线程号
pthread_t tid_m;//主线程号
void consumer()//消费者函数
{
   // while(1) //担心这个函数执行完了线程退出考虑加while(1)死循环,想在主函数用return终止这个线程,但是加上后只能写一次,读一次然后程序就不动了
//不加会先写一次,读一次,再写入两次。
    {
        pthread_mutex_lock(&mutex);//上锁
        int i=buffer.count;
        for(;buffer.count>0;buffer.count--)
        {
            printf("read %d is %d\n",buffer.count,buffer.product[i-buffer.count]);
        }
        pthread_mutex_unlock(&mutex);//解锁
        pthread_join(tid_m,NULL);//等待生产者线程输入数据完毕   问题在这里 需要新的知识解决
    }

}
void product()
{
    pthread_mutex_lock(&mutex);//上锁
    for(buffer.count=0;buffer.count<5;buffer.count++)
    {
         sleep((unsigned)rand()%3);//线程休眠
        buffer.product[buffer.count]=rand()%10;
        printf("write %d is %d   \n",buffer.count,buffer.product[buffer.count]);

    }
    pthread_mutex_unlock(&mutex);//解锁
    pthread_join(tid,NULL);//等待消费者线程 写数据完毕

}

int main()
{
    int ret,i;
    tid_m=pthread_self();//获取主线程的id
    time_t t;
    srand((unsigned)time(&t));//随机数模仿速度不固定
    memset(&buffer,0,sizeof(PRODUCT));//先清空缓冲区
    pthread_mutex_init(&mutex,NULL);//初始化互斥锁
    ret=pthread_create(&tid,NULL,(void*)consumer,NULL);//创建新线程
    if(ret!=0)
    {
        perror("ret");
        exit(0);
    }
    for(i=0;i<3;i++)//写三次
    {
       product();
    }
    pthread_mutex_unlock(&mutex);//销毁互斥锁
    return 0;
}

程序写入一次的时候,没有问题,但是写入三次的时候要么阻塞,要么不读去以后的写入,这里只是看到了互斥锁的特点,但是没有解决最终问题。还需要条件变量的知识。下面是修正后的程序,用到了条件变量,这个变量是用来对线程进行阻塞的。

#include <stdio.h>
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define WRITE_TIMES 3 //生产次数
typedef struct
{
    int product[5];
    int count;
}
PRODUCT;
PRODUCT buffer;//缓冲区结构,消费者和生产者共同操作
pthread_mutex_t mutex;//创建互斥锁
pthread_cond_t cond;//创建条件变量
pthread_t tid;//新线程号
pthread_t tid_m;//主线程号
void consumer()//消费者函数
{
    static int T=0;
    int i=0;
    while(T<WRITE_TIMES)
    {
        pthread_mutex_lock(&mutex);//上锁
        while(buffer.count!=5)
        {   //当初不知道pthread_cond_wait函数加在哪里,忽视了线程共享同一进程的资源。
            pthread_cond_wait(&cond,&mutex);//等待信号
        }
        i=buffer.count;
        for(;buffer.count>0;buffer.count--)
        {
            printf("read %d is %d\n",buffer.count,buffer.product[i-buffer.count]);
        }
        pthread_mutex_unlock(&mutex);//解锁
        T++;
     }
}
void product()
{
    pthread_mutex_lock(&mutex);//上锁
    for(buffer.count=0;buffer.count<5;buffer.count++)
    {
       // sleep((unsigned)rand()%2);//线程休眠,这里是模仿速度不固定,验证互斥锁是否其作用
        buffer.product[buffer.count]=rand()%10;
        printf("write %d is %d   \n",buffer.count,buffer.product[buffer.count]);
    }
    pthread_cond_signal(&cond);//接触消费者线程的锁定状态
    pthread_mutex_unlock(&mutex);//解锁
    sleep(1);//必须有,否则CPU执行速度太快,生产者线程来不及切换,导致生产WRITE_MAX次,只消费一次
}

int main()
{
    int ret,i;
    tid_m=pthread_self();//获取主线程的id
    time_t t;
    srand((unsigned)time(&t));//随机数模仿速度不固定
    memset(&buffer,0,sizeof(PRODUCT));//先清空缓冲区
    pthread_mutex_init(&mutex,NULL);//初始化互斥锁
    pthread_cond_init(&cond,NULL);//初始化条件变量
    ret=pthread_create(&tid,NULL,(void*)consumer,NULL);//创建新线程
    if(ret!=0)
    {
        printf("create thread fail \n");
        exit(0);
    }
    for(i=0;i<WRITE_TIMES;i++)//生产WRITE——TIMES次
    {
       product();
    }
    pthread_join(tid,NULL);//等待消费者线程退出,生产者线程就是主线程,最后return退出
    pthread_mutex_unlock(&mutex);//销毁互斥锁
    pthread_cond_destroy(&cond);
    return 0;
}

现在思考下第一次为什么失败,当初理解有误,pthread_join函数是等待线程退出,类似与进程里面的wait_pid函数,而我理解成了阻塞当前线程,是不对的,首先我在product里面,最后等待新的线程执行完,然后新的线程开始执行,但是新的线程执行了后,我又调用pthread_join等待主线程结束,我当时认为这是只是阻塞线程,CPU会进行调度的,其实这两个线程你等着我死,我等着你死,然后就出现了程序不继续运行的情况了。

下面才是正确的执行情况,写三次,读取三次。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值