文章目錄
- POSIX信號量
- 是什么?
- 信號量的意義?
- 怎么用?
- 基于環形佇列的生產消費模型
POSIX信號量
是什么?
信號量(也叫信號燈),本質是一個在描述臨界資源中,有效資源個數的計數器,
如果把臨界區劃分成多個塊兒,那么多個執行緒可以同時進入臨界區訪問不同的塊,
之前的鎖,是我們認為臨界資源只有一塊,
信號量可以保證讓多個執行緒同時進入臨界區,訪問臨界資源的不同塊,
申請信號量,把計數器--叫做P操作;釋放信號量,計數器++叫做V操作,
要保證所有的執行緒都得看到信號量,所以信號量本身就是臨界資源,因此得保證它的安全,
因此PV操作一定是原子的,
信號量的意義?
臨界資源可以劃分成多塊,
這樣就可以并行的訪問臨界資源,提高效率,
怎么用?
POSIX信號量和SystemV信號量作用相同,都是用于同步操作,達到無沖突的訪問共享資源的目的, 但POSIX可以用于執行緒間同步,
- 初始化信號量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
pshared:0表示執行緒間共享,非零表示行程間共享
value:信號量初始值
- 銷毀信號量
int sem_destroy(sem_t *sem);
- 等待信號量 - P操作:會將信號量的值減1
int sem_wait(sem_t *sem);
- 發布信號量 - V操作:會將信號量的值加1
int sem_post(sem_t *sem);
基于環形佇列的生產消費模型
環形佇列可以抽象成陣列,用模運算來模擬環狀特性,

生產者和消費者不指向同一個位置時,佇列不滿不空;而指向同一個位置時,佇列是滿或空的狀態,
也就是說,下標不同時,它們并行(同步);相同時,它們串行,(互斥)
該模型用信號量維持了生產者和消費者的同步與互斥,
- RingQueue.hpp
#pragma once
#include <iostream>
#include <vector>
#include <unistd.h>
#include <semaphore.h>
#define NUM 10
class RingQueue{
private:
void P(sem_t &s) // 參考
{
sem_wait(&s); // 取地址
}
void V(sem_t &s)
{
sem_post(&s);
}
public:
RingQueue(int _cap = NUM):max_cap(_cap), v(_cap)
{
sem_init(&sem_space, 0, max_cap); // 0 代表執行緒間共享,max_cap信號量初始值
sem_init(&sem_data, 0, 0); // 資料資源最初為0
c_index = 0;// 默認消費者從0開始走
p_index = 0;// 默認生產者從0開始走
}
void Put(const int &in)
{
P(sem_space); // 生產者,申請格子資源
v[p_index] = in; // 生產
p_index++;
p_index %= max_cap;
V(sem_data); // 多了一份資料資源
}
void Get(int &out)
{
P(sem_data); // 消費者,申請資料資源
out = v[c_index]; // 消費
c_index++;
c_index %= max_cap;
V(sem_space); // 消費完就多了一份格子資源
}
~RingQueue()
{
sem_destroy(&sem_space);
sem_destroy(&sem_data);
c_index = 0;
p_index = 0;
}
private:
int max_cap;
std::vector<int> v;
sem_t sem_space; // 生產者關心的格子資源
sem_t sem_data; // 消費者關心的資料資源
int c_index; // 決定了它使用臨界資源的哪一份
int p_index;
};
- main.cc
#include"RingQueue.hpp"
void* producer(void* ring_queue)
{
RingQueue* rq = (RingQueue*)ring_queue;
while(true)
{
int count = rand()%100 + 1;
sleep(1);
rq->Put(count); //生產
std::cout<< "producer is producing" << std::endl;
}
}
void* consumer(void* ring_queue)
{
RingQueue* rq = (RingQueue*)ring_queue;
while(true)
{
int data = 0;
rq->Get(data); // 消費
std::cout<< "consumer data: #" << data << std::endl;
}
}
int main()
{
pthread_t p,c;
RingQueue *rq = new RingQueue();
pthread_create(&p, nullptr, producer, rq);
pthread_create(&c, nullptr, consumer, rq);
pthread_join(p, nullptr);
pthread_join(c, nullptr);
delete rq;
return 0;
}
- Makefile
testRingQueue:main.cc
g++ $^ -o $@ -std=c++11 -lpthread
.PHONY:clean
clean:
rm -f testRingQueue
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/281423.html
標籤:其他
下一篇:介面測驗流程及用例設計
