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减少1sem_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加1sem_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;
}