12.线程同步和生产消费模型

一.上集回顾

建议先学上篇博客,再向下学习,上篇博客的链接如下:

https://blog.csdn.net/weixin_60668256/article/details/154576356?fromshare=blogdetail&sharetype=blogdetail&sharerId=154576356&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.条件变量的简单demo

1.上集回顾

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>

int ticket = 0;
pthread_mutex_t mutex;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *route(void *arg)
{
    char *id = (char*)arg;
    while (1) {
        pthread_mutex_lock(&mutex);
        if (ticket > 0) {
            usleep(1000);
            printf("%s sells ticket:%d\n", id, ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);
        } else {
            printf("%s wait on cond!\n",id);
            pthread_cond_wait(&cond,&mutex);//醒来的时候,会重新申请锁!!
            printf("%s 被叫醒了\n",id);
        }
        pthread_mutex_unlock(&mutex);
    }
    return nullptr;
}

int main(void)
{
    pthread_t t1, t2, t3, t4;

    pthread_mutex_init(&mutex, NULL);

    pthread_create(&t1, NULL, route, (void*)"thread_1");
    pthread_create(&t2, NULL, route, (void*)"thread_2");
    pthread_create(&t3, NULL, route, (void*)"thread_3");
    pthread_create(&t4, NULL, route, (void*)"thread_4");
    int cnt = 10;
    while(true)
    {
        sleep(5);
        ticket += cnt;
        printf("主线程放票咯! ticket: %d\n",ticket);
        pthread_cond_signal(&cond);
    }

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
}

不是只有一个线程能拿到对应的锁吗?为啥都会在条件变量下等呢?

2.简单demo

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <string>
#include <pthread.h>


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void* active(void* arg)
{
    std::string name = static_cast<const char*>(arg);
    while(true)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        printf("%s isactive!\n",name.c_str());
        pthread_mutex_unlock(&mutex);
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,nullptr,active,(void*)"thread-1");
    pthread_create(&tid2,nullptr,active,(void*)"thread-2");
    pthread_create(&tid3,nullptr,active,(void*)"thread-3");

    sleep(1);
    printf("Main thread ctrl begin...\n");

    while(true)
    {
        printf("main wakup thread...\n");
        pthread_cond_signal(&cond);
        sleep(1);
    }


    pthread_join(tid1,nullptr);
    pthread_join(tid2,nullptr);
    pthread_join(tid3,nullptr);
    return 0;
}
cpp 复制代码
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <string>
#include <pthread.h>


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void* active(void* arg)
{
    std::string name = static_cast<const char*>(arg);
    while(true)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        printf("%s isactive!\n",name.c_str());
        pthread_mutex_unlock(&mutex);
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,nullptr,active,(void*)"thread-1");
    pthread_create(&tid2,nullptr,active,(void*)"thread-2");
    pthread_create(&tid3,nullptr,active,(void*)"thread-3");

    sleep(1);
    printf("Main thread ctrl begin...\n");

    while(true)
    {
        printf("main wakup thread...\n");
        pthread_cond_broadcast(&cond);
        sleep(1);
    }


    pthread_join(tid1,nullptr);
    pthread_join(tid2,nullptr);
    pthread_join(tid3,nullptr);
    return 0;
}

三.生产者消费者模型

四.基于BlockingQueue的生产者消费者模型

1.单生成,单消费代码实现

a.main函数的实现

cpp 复制代码
#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>

using namespace BlockQueueModule;

void* Consumer(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    while(true)
    {
        int data;
        //1.从bq拿到数据
        bq->Pop(&data);
        //2.做处理
        sleep(1);
        printf("Consumer, get a data: %d\n",data);
    }
}

void* Productor(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    while(true)
    {
        //1.从外部获取数据
        int data = 10;
        //2.生产到bq中
        bq->Equeue(data);
    }
}

int main()
{
    BlockQueue<int>* bq = new BlockQueue<int>();//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c,p;
    pthread_create(&c,nullptr,Consumer,bq);
    pthread_create(&p,nullptr,Productor,bq);

    pthread_join(c,nullptr);
    pthread_join(p,nullptr);

    delete bq;
    return 0;
}

b.blockqueue的大致框架

cpp 复制代码
#pragma once

#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>

namespace BlockQueueModule
{
    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue()
        {
        }
        void Equeue(const T& in)
        {
        }
        void Pop(T* out)
        {
        }
        ~BlockQueue()
        {
        }
    private:
        std::queue<T> _q;              //保存数据的容器
        int _cap;                      //bq最大容量
        pthread_mutex_t _mutex;        //互斥
        pthread_cond_t _productor_cond;//生产者的条件变量
        pthread_cond_t _consumer_cond; //消费者的条件变量
    };
}

所以的线程互斥,线程同步的机制,都在我们对应的Equeue和Pop里面进行完成

c.BlockQueue函数的实现

cpp 复制代码
BlockQueue(int cap = gcap):_cap(cap)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }

d.~BlockQueue函数的实现

cpp 复制代码
~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }

e.其他函数的实现

cpp 复制代码
bool IsFull()
        {
            return _q.size() == _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }

f.Equeue函数的实现

cpp 复制代码
void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //想放数据也是要有条件的
            //1.在临界区中等待是必然的!
            if(IsFull())
            {
                //2.等待的时候,会释放_mutex
                pthread_cond_wait(&_productor_cond,&_mutex);//wait的时候,必定是持有锁的
                //3.返回,线程被唤醒 && 重新申请并持有锁(它会在临界区内醒来)
            }
            //4.到这里,我们一定可以进行生产了
            _q.push(in);

            pthread_mutex_unlock(&_mutex);
        }

g.Pop函数的实现

cpp 复制代码
void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            if(IsEmpty())
            {
                pthread_cond_wait(&_consumer_cond,&_mutex);
            }
            //到这里我们必定有数据
            *out = _q.fornt();
            _q.pop();

            pthread_mutex_unlock(&_mutex);
        }

这个Pop函数和上述的Equeue函数差不多

2.代码debug

上述的Equeue和我们的Pop有没有那里不对呢?

上述代码全部都在进行休眠,但是谁来将他们唤醒呢?

当没有资源时,消费者在进行等待,那么谁只有会有资源呢?(答案是生产者,所以当我们进行生产的时候,就将等待的消费者进行唤醒(前提是要有消费者),生产者等待时也同理)

所有,我们可以加上两个成员函数,来统计我们的生产者和消费者等待的个数

cpp 复制代码
int _cwait_num;
int _pwait_num;
cpp 复制代码
BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }

a.Equeue代码更新

cpp 复制代码
void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //想放数据也是要有条件的
            //1.在临界区中等待是必然的!
            if(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                //2.等待的时候,会释放_mutex
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);//wait的时候,必定是持有锁的
                _pwait_num--;
                //3.返回,线程被唤醒 && 重新申请并持有锁(它会在临界区内醒来)
                std::cout << "生产者被唤醒..." << std::endl;
            }
            //4.到这里,我们一定可以进行生产了
            _q.push(in);

            //一定有数据
            if(_cwait_num)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }

b.Pop代码更新

cpp 复制代码
void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            if(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            //到这里我们必定有数据
            *out = _q.fornt();
            _q.pop();

            //一定有空间
            if(_pwait_num)
            {
                pthread_cond_signal(&_productor_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }

c.生产者无限生产,消费者慢一点进行消费

cpp 复制代码
#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>

using namespace BlockQueueModule;

void* Consumer(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    while(true)
    {
        sleep(2);
        int data;
        //1.从bq拿到数据
        bq->Pop(&data);
        //2.做处理
        printf("Consumer, 消费了一个数据: %d\n",data);
    }
}

void* Productor(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    int data = 10;
    while(true)
    {
        //1.从外部获取数据
        //2.生产到bq中
        bq->Equeue(data);
        
        printf("productor 生产了一个数据: %d\n",data);
        data++;
    }
}

int main()
{
    BlockQueue<int>* bq = new BlockQueue<int>(5);//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c,p;
    pthread_create(&c,nullptr,Consumer,bq);
    pthread_create(&p,nullptr,Productor,bq);

    pthread_join(c,nullptr);
    pthread_join(p,nullptr);

    delete bq;
    return 0;
}

消费的是历史数据,生产的是新的数据

d.消费者先进行消费,然后生产者再进行生产

cpp 复制代码
#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>

using namespace BlockQueueModule;

void* Consumer(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    while(true)
    {
        int data;
        //1.从bq拿到数据
        bq->Pop(&data);
        //2.做处理
        printf("Consumer, 消费了一个数据: %d\n",data);
    }
}

void* Productor(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    int data = 10;
    while(true)
    {
        sleep(2);
        //1.从外部获取数据
        //2.生产到bq中
        bq->Equeue(data);
        
        printf("productor 生产了一个数据: %d\n",data);
        data++;
    }
}

int main()
{
    BlockQueue<int>* bq = new BlockQueue<int>(5);//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c,p;
    pthread_create(&c,nullptr,Consumer,bq);
    pthread_create(&p,nullptr,Productor,bq);

    pthread_join(c,nullptr);
    pthread_join(p,nullptr);

    delete bq;
    return 0;
}

在解锁之前和解锁之后等,都是可以的

单生成单消费这里,我们是不会出现啥问题的

五.多生产,多消费

1.代码整体修改

cpp 复制代码
"BlockQueue.hpp"


#pragma once

#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>


namespace BlockQueueModule
{
    static const int gcap = 10;
    template<class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _q.size() == _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }
        void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //想放数据也是要有条件的
            //1.在临界区中等待是必然的!
            if(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                //2.等待的时候,会释放_mutex
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);//wait的时候,必定是持有锁的
                _pwait_num--;
                //3.返回,线程被唤醒 && 重新申请并持有锁(它会在临界区内醒来)
                std::cout << "生产者被唤醒..." << std::endl;
            }
            //4.到这里,我们一定可以进行生产了
            _q.push(in);

            //一定有数据
            if(_cwait_num)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            if(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            //到这里我们必定有数据
            *out = _q.front();
            _q.pop();

            //一定有空间
            if(_pwait_num)
            {
                pthread_cond_signal(&_productor_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }
    private:
        std::queue<T> _q;              //保存数据的容器
        int _cap;                      //bq最大容量
        pthread_mutex_t _mutex;        //互斥
        pthread_cond_t _productor_cond;//生产者的条件变量
        pthread_cond_t _consumer_cond; //消费者的条件变量

        int _cwait_num;
        int _pwait_num;
    };
}

这里如果是单生成单消费,那么就没有问题,但是如果是我们对应的多生产和多消费,那么这样就行不通了,因为我们唤醒,是要将所有的代码进行唤醒,而不是只进行唤醒一个线程

cpp 复制代码
#pragma once

#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>


namespace BlockQueueModule
{
    static const int gcap = 10;
    template<class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _q.size() == _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }
        void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //想放数据也是要有条件的
            //1.在临界区中等待是必然的!
            while(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                //2.等待的时候,会释放_mutex
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);//wait的时候,必定是持有锁的
                _pwait_num--;
                //3.返回,线程被唤醒 && 重新申请并持有锁(它会在临界区内醒来)
                std::cout << "生产者被唤醒..." << std::endl;
            }
            //4.到这里,我们一定可以进行生产了
            _q.push(in);

            //一定有数据
            if(_cwait_num)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);//伪唤醒
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            //到这里我们必定有数据
            *out = _q.front();
            _q.pop();

            //一定有空间
            if(_pwait_num)
            {
                pthread_cond_signal(&_productor_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }
    private:
        std::queue<T> _q;              //保存数据的容器
        int _cap;                      //bq最大容量
        pthread_mutex_t _mutex;        //互斥
        pthread_cond_t _productor_cond;//生产者的条件变量
        pthread_cond_t _consumer_cond; //消费者的条件变量

        int _cwait_num;
        int _pwait_num;
    };
}
cpp 复制代码
#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>

using namespace BlockQueueModule;

void* Consumer(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    while(true)
    {
        int data;
        //1.从bq拿到数据
        bq->Pop(&data);
        //2.做处理
        printf("Consumer, 消费了一个数据: %d\n",data);
    }
}

void* Productor(void* args)
{
    BlockQueue<int>* bq = static_cast<BlockQueue<int>*>(args);
    int data = 10;
    while(true)
    {
        sleep(2);
        //1.从外部获取数据
        //2.生产到bq中
        bq->Equeue(data);
        
        printf("productor 生产了一个数据: %d\n",data);
        data++;
    }
}

int main()
{
    BlockQueue<int>* bq = new BlockQueue<int>(5);//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c1,c2,p1,p2,p3;
    pthread_create(&c1,nullptr,Consumer,bq);
    pthread_create(&c2,nullptr,Consumer,bq);
    pthread_create(&p1,nullptr,Productor,bq);
    pthread_create(&p2,nullptr,Productor,bq);
    pthread_create(&p3,nullptr,Productor,bq);

    pthread_join(c1,nullptr);
    pthread_join(c2,nullptr);
    pthread_join(p1,nullptr);
    pthread_join(p2,nullptr);
    pthread_join(p3,nullptr);

    delete bq;
    return 0;
}

这里我们创建了2个生产者,3个消费者(我们刚刚改了while,所以支持多生产多消费了)

2.封装(mutex)条件变量

a.条件变量框架搭建

cpp 复制代码
#pragma once


#include <iostream>
#include <pthread.h>

namespace CondModule
{
    class Cond
    {
    public:
        Cond()
        {
            int n = ::pthread_cond_init(&_cond,nullptr);
            (void)n;
        }
        ~Cond()
        {
            int n = ::pthread_cond_destroy(&_cond);
        }
    private:
        pthread_cond_t _cond;
    };
}

b.其他函数的封装

cpp 复制代码
#pragma once


#include <iostream>
#include <pthread.h>
#include "Mutex.hpp"



namespace CondModule
{
    using namespace LockModule;
    
    class Cond
    {
    public:
        Cond()
        {
            int n = ::pthread_cond_init(&_cond,nullptr);
            (void)n;
        }
        void Wait(Mutex& mutex)//让线程曾经的锁释放曾经的锁
        {
            int n = ::pthread_cond_wait(&_cond,mutex.LockPtr());
            (void)n;
        }
        void Notify()
        {
            int n = ::pthread_cond_signal(&_cond);
            (void)n;
        }
        void NotifyAll()
        {
            int n = ::pthread_cond_broadcast(&_cond);
            (void)n;
        }
        ~Cond()
        {
            int n = ::pthread_cond_destroy(&_cond);
            (void)n;
        }
    private:
        pthread_cond_t _cond;
    };
}

3.封装BlockQueue

cpp 复制代码
#pragma once

#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"


namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;
    static const int gcap = 10;
    template<class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _q.size() == _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
        {
        }
        void Equeue(const T& in)
        {
            LockGuard lockguard(_mutex);
            while(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                _pwait_num++;
                _productor_cond.Wait(_mutex);
                _pwait_num--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            _q.push(in);

            if(_cwait_num)
            {
                _consumer_cond.Notify();
            }
        }
        void Pop(T* out)
        {
            LockGuard lockguard(_mutex);
            while(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                _consumer_cond.Wait(_mutex);
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            //到这里我们必定有数据
            *out = _q.front();
            _q.pop();

            //一定有空间
            if(_pwait_num)
            {
                _productor_cond.Notify();
            }
        }
        ~BlockQueue()
        {
        }
    private:
        std::queue<T> _q;              //保存数据的容器
        int _cap;                      //bq最大容量
        Mutex _mutex;        //互斥
        Cond _productor_cond;//生产者的条件变量
        Cond _consumer_cond; //消费者的条件变量

        int _cwait_num;
        int _pwait_num;
    };
}

六.传递任务

1.场景1

cpp 复制代码
"Task.hpp"



#pragma once

#include <iostream>
#include <unistd.h>


namespace TaskModule
{
    class Task
    {
    public:
        Task()
        {}
        Task(int a,int b):x(a),y(b)
        {

        }
        void Excute()
        {
            sleep(1);//模拟任务处理时长
            result = x + y;
        }
        int X()
        {
            return x;
        }
        int Y()
        {
            return y;
        }
        int Result()
        {
            return result;
        }
        ~Task()
        {}
    private:
        int x;
        int y;
        int result;
    };
}
cpp 复制代码
#include "BlockQueue.hpp"
#include "Task.hpp"
#include <pthread.h>
#include <unistd.h>
#include <ctime>


using namespace BlockQueueModule;
using namespace TaskModule;
void* Consumer(void* args)
{
    BlockQueue<Task>* bq = static_cast<BlockQueue<Task>*>(args);
    while(true)
    {
        Task t;
        //1.从bq拿到数据
        bq->Pop(&t);
        //2.做处理
        t.Excute();
        printf("Consumer, 处理了一个任务: %d+%d=%d\n",t.X(),t.Y(),t.Result());
    }
}

void* Productor(void* args)
{
    BlockQueue<Task>* bq = static_cast<BlockQueue<Task>*>(args);
    int data = 10;
    while(true)
    {
        //1.从外部获取数据
        int x = rand() % 10 + 1;
        int y = rand() % 20 + 1;
        Task t(x,y);
        //2.生产到bq中
        bq->Equeue(t);
        
        printf("productor 生产了一个任务: %d+%d=?\n",t.X(),t.Y());
    }
}

int main()
{
    srand(time(nullptr) ^ getpid());
    BlockQueue<Task>* bq = new BlockQueue<Task>(5);//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c1,c2,p1,p2,p3;
    pthread_create(&c1,nullptr,Consumer,bq);
    pthread_create(&c2,nullptr,Consumer,bq);
    pthread_create(&p1,nullptr,Productor,bq);
    pthread_create(&p2,nullptr,Productor,bq);
    pthread_create(&p3,nullptr,Productor,bq);

    pthread_join(c1,nullptr);
    pthread_join(c2,nullptr);
    pthread_join(p1,nullptr);
    pthread_join(p2,nullptr);
    pthread_join(p3,nullptr);

    delete bq;
    return 0;
}

2.场景2

cpp 复制代码
#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include <functional>

void test()
{
    std::cout << "haha test..." << std::endl;
}
void hello()
{
    std::cout << "hehe hello..." << std::endl;
}
using task_t = std::function<void()>;

using namespace BlockQueueModule;



void* Consumer(void* args)
{
    BlockQueue<task_t>* bq = static_cast<BlockQueue<task_t>*>(args);
    while(true)
    {
        task_t t;
        //1.从bq拿到数据
        bq->Pop(&t);
        //2.做处理
        t();
    }
}

void* Productor(void* args)
{
    BlockQueue<task_t>* bq = static_cast<BlockQueue<task_t>*>(args);
    int data = 10;
    while(true)
    {
        sleep(1);
        bq->Equeue(test);
    }
}

int main()
{
    srand(time(nullptr) ^ getpid());
    BlockQueue<task_t>* bq = new BlockQueue<task_t>(5);//共享资源 -> 临界资源
    //单生产,单消费
    pthread_t c1,c2,p1,p2,p3;
    pthread_create(&c1,nullptr,Consumer,bq);
    pthread_create(&c2,nullptr,Consumer,bq);
    pthread_create(&p1,nullptr,Productor,bq);
    pthread_create(&p2,nullptr,Productor,bq);
    pthread_create(&p3,nullptr,Productor,bq);

    pthread_join(c1,nullptr);
    pthread_join(c2,nullptr);
    pthread_join(p1,nullptr);
    pthread_join(p2,nullptr);
    pthread_join(p3,nullptr);

    delete bq;
    return 0;
}

7.补充

生产者消费者,要串行执行那么高效在哪里呢?

生产者在获取任务的时候,消费者可以从区域上拿任务,还可以进行处理任务

消费者处理数据的时候,生产者可以从外部拿数据

相关推荐
沙威玛_LHE2 小时前
C++ 头文件:语言功能的 “模块化工具箱”(第三章)
c++
snakecy2 小时前
常用命令记录
linux·运维·github
顺顺 尼2 小时前
了解和使用多态
c++
学习编程的Kitty2 小时前
JavaEE初阶——多线程(5)单例模式和阻塞队列
java·开发语言·单例模式
cccyi72 小时前
Linux Socket 编程全解析:UDP 与 TCP 实现及应用
linux·tcp socket·udp socket
0x00072 小时前
翻译《The Old New Thing》- 为什么 SHFormatDateTime 要接收一个未对齐的 FILETIME?
c++·windows
懒羊羊不懒@2 小时前
JavaSe—Stream流☆
java·开发语言·数据结构
小苏兮2 小时前
【把Linux“聊”明白】自动化构建-make/Makefile详解
linux·服务器·学习·自动化·1024程序员节
Js_cold3 小时前
(* clock_buffer_type=“NONE“ *)
开发语言·fpga开发·verilog·vivado·buffer·clock