3.14、信号量
1.信号量的介绍
-
信号量则是一种计数器,可以用来同步多个线程之间的操作。当线程需要访问某个受保护的资源时,它需要先获取信号量。如果信号量的值大于零,表示当前没有线程访问该资源,线程可以获取该资源并将信号量的值减一;否则,线程需要等待,直到有其他线程释放了该资源并增加了信号量的值。
-
在锁中使用信号量,通常是为了解决生产者消费者问题。在生产者消费者问题中,有一个缓冲区用于存放生产者生产的数据,消费者需要从缓冲区中取出数据进行消费。当缓冲区为空时,消费者需要等待生产者生产数据并通知消费者;当缓冲区满时,生产者需要等待消费者消费数据并通知生产者。
2.信号量的相关函数
- 信号量的类型
sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
初始化一个信号量。int sem_destroy(sem_t *sem);
销毁并释放信号量资源int sem_wait(sem_t *sem);
等待信号量,如果信号量值为0,则阻塞等待,否则减少信号量值并返回。int sem_trywait(sem_t *sem);
尝试等待,不阻塞int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
等待多久int sem_getvalue(sem_t *sem, int *sval);
获取信号量中的值
3.信号量函数的使用介绍
信号量的类型 sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 初始化信号量
- 参数:
- sem : 信号量变量的地址
- pshared : 0 用在线程间 ,非0 用在进程间
- value : 信号量中的值
int sem_destroy(sem_t *sem);
- 释放资源
int sem_wait(sem_t *sem);
- 对信号量加锁,调用一次对信号量的值-1,如果值为0,就阻塞
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
- 对信号量解锁,调用一次对信号量的值+1
4.用信号量实现生产者消费者模型
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;
// 创建互斥锁
pthread_mutex_t mutex;
// 创建信号量
sem_t psem, csem;
struct Node
{
int num;
Node * next;
Node(): num(0), next(nullptr) {
}
Node(int _num): num(_num), next(nullptr) {
}
};
Node * head = nullptr;
void * producer(void * arg)
{
while (1)
{
// psem减少1
sem_wait(&psem);
// 加锁
pthread_mutex_lock(&mutex);
Node * newNode = new Node(rand() % 1000);
newNode->next = head;
head = newNode;
printf ("add node, num: %d, tid: %ld\n", newNode->num, pthread_self());
// 解锁
pthread_mutex_unlock(&mutex);
// csem加1
sem_post(&csem);
usleep(100);
}
pthread_exit(nullptr);
}
void * customer(void * arg)
{
while (1)
{
sem_wait(&csem);
pthread_mutex_lock(&mutex);
Node * tmp = head;
head = head->next;
printf ("del node, num: %d, tid: %ld\n", tmp->num, pthread_self());
delete tmp;
tmp = nullptr;
pthread_mutex_unlock(&mutex);
sem_post(&psem);
usleep(100);
}
pthread_exit(nullptr);
}
int main()
{
// 初始化互斥锁和信号量
pthread_mutex_init(&mutex, nullptr);
sem_init(&psem, 0, 10);
sem_init(&csem, 0, 0);
// 创建5个生产者和5个消费者
pthread_t ptid[5], ctid[5];
for (int i = 0; i < 5; i ++ )
{
pthread_create(&ptid[i], nullptr, producer, nullptr);
pthread_create(&ctid[i], nullptr, customer, nullptr);
}
// 主线程回收线程
for (int i = 0; i < 5; i ++ )
{
pthread_join(ptid[i], nullptr);
pthread_join(ctid[i], nullptr);
}
// 释放锁和信号量
ptherad_mutex_destory(&mutex);
sem_destroy(&psem);
sem_destroy(&csem);
pthread_exit(nullptr);
return 0;
}