信号量
信号量的本质是一个计数器,可以用来衡量临界资源中资源数量多少
信号量的PV操作
P操作:申请信号量称为P操作,P操作的本质就是让计数器减1。
V操作:释放信号量称为V操作,V操作的本质就是让计数器加1
POSIX信号量相关的接口函数
初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:需要初始化的信号量。
pshared:0表示线程间共享,非0表示进程间共享。
value:信号量的初始值(特定资源的初始数量)。
等待信号量(P操作)
int sem_wait(sem_t *sem);
发布信号量(V操作)
int sem_post(sem_t *sem);
销毁信号量
int sem_destroy(sem_t *sem);
基于环形队列的生产消费模型代码
RingQueue.hpp
#pragma once #include <iostream> #include <vector> #include <cassert> #include <semaphore.h> #include <pthread.h> static const int gcap = 5; template<class T> class RingQueue { private: void P(sem_t &sem) { int n = sem_wait(&sem); assert(n == 0); // if (void)n; } void V(sem_t &sem) { int n = sem_post(&sem); assert(n == 0); (void)n; } public: RingQueue(const int &cap = gcap): _queue(cap), _cap(cap) { int n = sem_init(&_spaceSem, 0, _cap); assert(n == 0); n = sem_init(&_dataSem, 0, 0); assert(n == 0); _productorStep = _consumerStep = 0; pthread_mutex_init(&_pmutex, nullptr); pthread_mutex_init(&_cmutex, nullptr); } // 生产者 void Push(const T &in) { //先申请信号量,在加锁 P(_spaceSem); pthread_mutex_lock(&_pmutex); _queue[_productorStep++] = in; _productorStep %= _cap; pthread_mutex_unlock(&_pmutex); V(_dataSem); } // 消费者 void Pop(T *out) { //先申请信号量,在加锁 P(_dataSem); pthread_mutex_lock(&_cmutex); *out = _queue[_consumerStep++]; _consumerStep %= _cap; pthread_mutex_unlock(&_cmutex); V(_spaceSem); } ~RingQueue() { sem_destroy(&_spaceSem); sem_destroy(&_dataSem); pthread_mutex_destroy(&_pmutex); pthread_mutex_destroy(&_cmutex); } private: std::vector<T> _queue; int _cap; sem_t _spaceSem; // 生产者的空间资源 sem_t _dataSem; // 消费者的数据资源 int _productorStep; int _consumerStep; pthread_mutex_t _pmutex; pthread_mutex_t _cmutex; };
Task.hpp
#pragma once #include <iostream> #include <string> #include <cstdio> #include <functional> class Task { using func_t = std::function<int(int,int,char)>; // typedef std::function<int(int,int)> func_t; public: Task() {} Task(int x, int y, char op, func_t func) :_x(x), _y(y), _op(op), _callback(func) {} std::string operator()() { int result = _callback(_x, _y, _op); char buffer[1024]; snprintf(buffer, sizeof buffer, "%d %c %d = %d", _x, _op, _y, result); return buffer; } std::string toTaskString() { char buffer[1024]; snprintf(buffer, sizeof buffer, "%d %c %d = ?", _x, _op, _y); return buffer; } private: int _x; int _y; char _op; func_t _callback; }; const std::string oper = "+-*/%"; int mymath(int x, int y, char op) { int result = 0; switch (op) { case '+': result = x + y; break; case '-': result = x - y; break; case '*': result = x * y; break; case '/': { if (y == 0) { std::cerr << "div zero error!" << std::endl; result = -1; } else result = x / y; } break; case '%': { if (y == 0) { std::cerr << "mod zero error!" << std::endl; result = -1; } else result = x % y; } break; default: // do nothing break; } return result; }
main.cc
#include "RingQueue.hpp" #include "Task.hpp" #include <pthread.h> #include <ctime> #include <cstdlib> #include <sys/types.h> #include <unistd.h> std::string SelfName() { char name[128]; snprintf(name, sizeof(name), "thread[0x%x]", pthread_self()); return name; } void *ProductorRoutine(void *rq) { RingQueue<Task> *ringqueue = static_cast<RingQueue<Task> *>(rq); while(true) { int x = rand() % 10; int y = rand() % 5; char op = oper[rand()%oper.size()]; Task t(x, y, op, mymath); // 生产任务 ringqueue->Push(t); // 输出提示 std::cout << SelfName() << ", 生产者派发了一个任务: " << t.toTaskString() << std::endl; sleep(1); } } void *ConsumerRoutine(void *rq) { RingQueue<Task> *ringqueue = static_cast<RingQueue<Task> *>(rq); while(true) { Task t; //消费任务 ringqueue->Pop(&t); std::string result = t(); std::cout << SelfName() << ", 消费者消费了一个任务: " << result << std::endl; } } int main() { srand((unsigned int)time(nullptr) ^ getpid() ^ pthread_self() ^ 0x71727374); RingQueue<Task> *rq = new RingQueue<Task>(); pthread_t p[4], c[8]; for(int i = 0; i < 4; i++) pthread_create(p+i, nullptr, ProductorRoutine, rq); for(int i = 0; i < 8; i++) pthread_create(c+i, nullptr, ConsumerRoutine, rq); for(int i = 0; i < 4; i++) pthread_join(p[i], nullptr); for(int i = 0; i < 8; i++) pthread_join(c[i], nullptr); delete rq; return 0; }