三 Linux--多线程( 二 )

基本方法的封装我对阻塞队列的一些基本操作进行了封装,有以下几个处理动作(可以设置为私有方法):

  • 判断队列为空或为满
  • 唤醒生产者和唤醒消费者
  • 生产者挂起等待和消费者挂起等待
  • 加锁和解锁
private:bool IsFull(){return _q.size() == _capacity;}bool IsEmpty(){return _q.empty();}void ConsumerWait(){cout << "consumer wait...." << endl;pthread_cond_wait(&_c_cond, &_lock);}void WakeUpConsumer(){cout << "wake up consumer...." << endl;pthread_cond_broadcast(&_c_cond);}void ProductorWait(){cout << "productor wait...." << endl;pthread_cond_wait(&_p_cond, &_lock);}void WakeUpProductor(){cout << "wake up productor...." << endl;pthread_cond_broadcast(&_p_cond);}void LockQueue(){pthread_mutex_lock(&_lock);}void UnLockQueue(){pthread_mutex_unlock(&_lock);}放数据和取数据
  • 生产者进行相关操作前先上锁,队列如果为满就需要挂起等待 。队列不为满就生成一个数据,然后需要把数据放入阻塞队列中,解开锁之后唤醒消费者,喊消费者进行消费 。
  • 消费者进行相关操作前先上锁,队列如果为空就需要挂起等待 。队列不为空就需要从阻塞队列中取一个数据,然后解开锁之后唤醒消费者,喊生产者进行生产 。
void ProductData(T data){LockQueue();while (IsFull()){// 让productor挂起等待ProductorWait();}// 放数据_q.push(data);UnLockQueue();// 唤醒consumerWakeUpConsumer();}void ConsumeData(T& data){LockQueue();while (IsEmpty()){// 让consumer挂起等待ConsumerWait();}// 取数据data = https://www.huyubaike.com/biancheng/_q.front();_q.pop();UnLockQueue();// 唤醒productorWakeUpProductor();}注意: 在临界资源判断唤醒条件是否就绪应该使用while循环检测,被唤醒的线程并不着急立即往下执行,而是再进行一次检测,判断当前唤醒条件是否真的就绪了 。因为唤醒线程的这个函数调用可能会发生失败,且线程可能是在条件不满足的时候被唤醒,发生误判被伪唤醒 。
封装一个任务我们可以实现一个任务类,生产者把这个任务放进阻塞队列中,消费者取出并进行处理 。其中还有一个run的任务执行方法
class Task{public:Task(int a = 0, int b = 0):_a(a),_b(b){}int Run(){return _a + _b;}int GetA(){return _a;}int GetB(){return _b;}private:int _a;int _b;};单生产者和单消费者模型分析BlockQueue<Task>* q;// 阻塞队列void* Consumer(void* arg){long id = (long)arg;while (1){// 消费(取)数据Task t(0, 0);q->ConsumeData(t);cout << "consumer " << id << " consumes a task: " << t.GetA() << " + " << t.GetB() << " = " << t.Run() << endl;sleep(1);// 后面可注释,调整速度}}void* Productor(void* arg){long id = (long)arg;while (1){// 生产(放)数据int x = rand()%10 + 1;int y = rand()%10 + 1;Task t(x, y);cout << "productor " << id << " produncs a task: " << x << " + " << y << " = ?" << endl;q->ProductData(t);sleep(1);// 后面可注释,调整速度}}int main(){srand((size_t)time(nullptr));// 创建一个交易场所q =new BlockQueue<Task>;pthread_t p, c;pthread_create(&p, nullptr, Productor, (void*)(1));pthread_create(&c, nullptr, Consumer, (void*)(1));pthread_join(p, nullptr);pthread_join(c, nullptr);delete q;return 0;}代码运行的结果分三种情况分析:
1.消费者和生产者以相同的速度执行
三 Linux--多线程

文章插图
可以看出的是,生产者生成完一个任务,消费者就处理了一个任务 。接着生产者继续生产,消费者跟着处理,二者步调一致,一直并行的状态
2.生产者快,消费者慢

经验总结扩展阅读