全文约 2409 字,预计阅读时长: 7分钟
POSIX信号量
将临界资源分成多份,支持多线程并发同步。互斥锁能保护临界资源,条件变量能帮我们直到临界资源的状态。信号量是一种资源的预定机制。线程来了,获取信号量,有资源就进去执行,执行完毕,让出资源;获取信号量时没有资源,则挂起等待。信号量本身也是一种临界资源,所以其P(申请资源)V(释放资源操作)操作是原子性的。
- 操作系统提供了一种信号量类型:
sem_t
- 初始化信号量:
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 参数:pshared:0表示线程间共享,非零表示进程间共享。一般设置为0.
value
:信号量初始值,多少份临界资源。
- 销毁信号量:
int sem_destroy(sem_t *sem);
- 等待信号量:
int sem_wait(sem_t *sem);
- 会将信号量的值减1,等同于:
sem--
;大于0,立即返回;反之则阻塞等待。
- 会将信号量的值减1,等同于:
- 发布信号量:
int sem_post(sem_t *sem);
- 会将信号量的值加1,等同于:
sem++
。
- 会将信号量的值加1,等同于:
基于环形队列的生产消费模型
- 环形队列采用数组模拟,用模运算来模拟环状特性。
- 生产者优先执行;差一个为满;不空不满,消费者生产者同时执行。现在结合信号量这个计数器,就很简单的进行多线程间的同步过程。
- 计算【1–N】之间的和:
---//hpp
#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
template <class T>
class RingQueue{
private:
int cap;
std::vector<T> ring;
//生产和消费必须有自己的位置下标
int c_index;
int p_index;
pthread_mutex_t c_lock;//多个消费线程
pthread_mutex_t p_lock;//多个生产线程 都要保证互斥
sem_t sem_space;
sem_t sem_data;
public:
RingQueue(int _cap):cap(_cap), ring(_cap), c_index(0), p_index(0)
{
pthread_mutex_init(&c_lock, nullptr);
pthread_mutex_init(&p_lock, nullptr);
sem_init(&sem_space, 0, _cap);
sem_init(&sem_data, 0, 0);
}
void Put(const T &in)
{
sem_wait(&sem_space);
//lock //生产者
ring[p_index] = in;
sem_post(&sem_data);
p_index++;
p_index %= cap;
//unlock
}
void Get(T *out)
{
sem_wait(&sem_data);
//lock 消费者
*out = ring[c_index];
sem_post(&sem_space);
c_index++;
c_index %= cap;
//unlock
}
~RingQueue()
{
pthread_mutex_destroy(&c_lock);
pthread_mutex_destroy(&p_lock);
sem_destroy(&sem_space);
sem_destroy(&sem_data);
}
};
---//main.cc
#include "RingQueue.hpp"
#include "Task.hpp"
#include <pthread.h>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
void *consumer(void *ring_queue)
{
RingQueue<Task> *rq = (RingQueue<Task>*)ring_queue;
while(true){
//sleep(1);
//1. 消费任务
Task t;
rq->Get(&t);
//2. 处理任务
int result = t.Handler();
std::cout << "消费者: hander Task Done , result: " << result << std::endl;
}
}
void *producter(void *ring_queue)
{
RingQueue<Task> *rq = (RingQueue<Task>*)ring_queue;
while(true){
//1. 制造任务, 或者别人给你的
int top = rand()%20000+1; //[1, 2000]
Task t(top);
t.Show();
//2. 生产任务
rq->Put(t);
}
}
int main()
{
RingQueue<Task> *rq = new RingQueue<Task>(10);
pthread_t c, p;
pthread_create(&c, nullptr, consumer, rq);
pthread_create(&p, nullptr, producter, rq);
pthread_join(c, nullptr);
pthread_join(p, nullptr);
return 0;
}
---//任务.hpp
#include <iostream>
class Task{
private:
int top; //[1,top]
public:
Task()
:top(1)
{}
Task(int _top)
:top(_top)
{}
int Handler()
{
int sum = 0;
for(auto i= 0; i <= top; i++){
sum += i;
}
return sum;
}
void Show()
{
std::cout << "生产者:这个任务是:累加数据从1~" << top << std::endl;
}
~Task()
{}
};
寄语
- …