目录
一,初始化信号量
使用sem_init细则:第三个参数为信号量的数量
二,为什么需要先申请信号量再加锁?
回答:先申请信号量可以节省申请信号量的时间,线程在申请锁处等待即可。如果先申请信号量则只能串行执行申请信号量和锁。
二,多生产多消费对比单生产单消费:
不管是那种类型,都只能一个线程生产一个线程消费,但是多生产多消费的意义在于节省了生产者生产任务和消费者消费任务的时间。而消耗时间占比更多的是生产任务和消费任务的时间。
三,源码:
1,task.hpp
#pragma once
#include<iostream>
#include<functional>
// typedef std::function<void()> task_t;
// using task_t = std::function<void()>;
// void Download()
// {
// std::cout << "我是一个下载的任务" << std::endl;
// }
// 要做加法
class Task
{
public:
Task()
{
}
Task(int x, int y) : _x(x), _y(y)
{
}
void Excute()
{
_result = _x + _y;
}
void operator ()()
{
Excute();
}
std::string debug()
{
std::string msg = std::to_string(_x) + "+" + std::to_string(_y) + "=?";
return msg;
}
std::string result()
{
std::string msg = std::to_string(_x) + "+" + std::to_string(_y) + "=" + std::to_string(_result);
return msg;
}
private:
int _x;
int _y;
int _result;
};
2,ringqueue.hpp
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
template <class T>
class Ringqueue
{
private:
void P(sem_t &s)
{
sem_wait(&s);
}
void V(sem_t &s)
{
sem_post(&s);
}
public:
Ringqueue(int max_cap)
: _ringqueue(max_cap),_max_cap(max_cap), _c_step(0), _p_step(0)
{
sem_init(&data_sem, 0, 0);
sem_init(&space_sem, 0, max_cap);
pthread_mutex_init(&_c_mutex, nullptr);
pthread_mutex_init(&_p_mutex, nullptr);
}
void push(T *in)
{
P(space_sem);
pthread_mutex_lock(&_p_mutex);
_ringqueue[_p_step] = *in;
_p_step++;
_p_step %= _max_cap;
pthread_mutex_unlock(&_p_mutex);
V(data_sem);
}
void Pop(T *out)
{
P(data_sem);
pthread_mutex_lock(&_c_mutex);
*out = _ringqueue[_c_step];
_c_step++;
_c_step %= _max_cap;
pthread_mutex_unlock(&_c_mutex);
V(space_sem);
}
~Ringqueue()
{
sem_destroy(&data_sem);
sem_destroy(&space_sem);
pthread_mutex_destroy(&_c_mutex);
pthread_mutex_destroy(&_p_mutex);
}
private:
std::vector<T> _ringqueue;
int _max_cap;
int _c_step;
int _p_step;
sem_t data_sem; // 消费者关心
sem_t space_sem; // 生产者关心
pthread_mutex_t _c_mutex;
pthread_mutex_t _p_mutex;
};
3,main.cc
#include "ringqueue.hpp"
#include "task.hpp"
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <ctime>
void *Consumer(void *args)
{
Ringqueue<Task> *rq = static_cast<Ringqueue<Task> *>(args);
while (1)
{
sleep(1);
Task ta;
rq->Pop(&ta);
ta();
std::cout << "Comsumer->" << ta.result() << std::endl;
}
}
void *Producer(void *args)
{
Ringqueue<Task> *rq = static_cast<Ringqueue<Task> *>(args);
while (true)
{
// 1. 构造数据
int x = rand() % 10 + 1; //[1, 10]
usleep(x * 1000);
int y = rand() % 10 + 1;
Task t(x, y);
// 2. 生产
rq->push(&t);
std::cout << "Productor -> " << t.debug() << std::endl;
}
}
int main()
{
srand(time(nullptr));
Ringqueue<Task> *rq = new Ringqueue<Task>(5);
pthread_t a, b, c;
pthread_t d, e, f, g;
pthread_create(&c, nullptr, Consumer, rq);
pthread_create(&a, nullptr, Consumer, rq);
pthread_create(&b, nullptr, Consumer, rq);
pthread_create(&d, nullptr, Producer, rq);
pthread_create(&e, nullptr, Producer, rq);
pthread_create(&f, nullptr, Producer, rq);
pthread_create(&g, nullptr, Producer, rq);
pthread_join(c, nullptr);
pthread_join(a, nullptr);
pthread_join(b, nullptr);
pthread_join(d, nullptr);
pthread_join(e, nullptr);
pthread_join(f, nullptr);
pthread_join(g, nullptr);
return 0;
}