信号量是一种同步机制,用于控制多个线程或进程对共享资源的访问。信号量本质上是一个计数器,它记录了可用资源的数量。当线程或进程需要访问共享资源时,它首先会检查信号量的值。如果信号量的值大于0,表示有可用的资源,线程或进程会减少信号量的值并继续执行。如果信号量的值为0,表示没有可用的资源,线程或进程会被阻塞,直到信号量的值增加。
要使用信号量,需要了解以下几个函数:
(1).初始化信号量函数sem_init
int sem_init(sem_t *sem, int pshared, unsigned value);
sem:代表指向信号量对象的指针;
pshared:代表信号量是在进程内共享(值为0)还是在进程间共享(非0);
value
:指定信号量的初始值。
若函数执行成功,返回1,若失败返回-1。
(2).信号量销毁函数sem_destroy
int sem_destroy(sem_t *sem);
sem:代表指向信号量对象的指针。
若函数执行成功,返回1,若失败返回-1。
(3)sem_wait
函数
sem_wait
是一个用于减少信号量值的函数,它的作用是尝试获取信号量,如果信号量的值为0,则线程会被阻塞,直到信号量的值增加为止。sem_wait函数的定义如下:
int sem_wait(sem_t *sem);
sem:代表指向信号量对象的指针。
若函数执行成功,返回1,若失败返回-1。
(4) sem_post函数
sem_post
是一个用于增加信号量值的函数,其作用是唤醒等待该信号量的进程。当一个进程完成对某个共享资源的使用后,可以使用sem_post
函数来唤醒等待该资源的后续进程,确保前后进程的执行顺序。
int sem_post(sem_t *sem);
sem:代表指向信号量对象的指针。
若函数执行成功,返回1,若失败返回-1。
?
?老样子,通过用信号量实现简单的生产者-消费者模型说明这四个函数的用法.代码如下:
// 引入必要的头文件
#include <pthread.h>
#include<string.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<iostream>
#include <semaphore.h>
// 定义一个互斥锁,用于保护共享资源
pthread_mutex_t mutex;
// 定义两个信号量对象,分别代表生产者和消费者的生产/消费权限
sem_t producer, consumer;
// 初始化产品数为0
int product = 0;
// 生产者线程函数
void* Producer(void* str) {
while (1) { // 无限循环,模拟持续生产
sem_wait(&producer); // 生产者等待生产权限
pthread_mutex_lock(&mutex); // 获取互斥锁,保护共享资源
product++; // 产品数加1
std::cout << "生产者:产品数为:" << product << std::endl; // 输出当前产品数
pthread_mutex_unlock(&mutex); // 释放互斥锁
sem_post(&consumer); // 释放消费者消费权限
sleep(1); // 生产后休眠1秒
}
return NULL; // 返回空指针,表示线程正常结束
}
// 消费者线程函数
void* Consumer(void* str) {
while (1) { // 无限循环,模拟持续消费
sem_wait(&consumer); // 消费者等待消费权限
pthread_mutex_lock(&mutex); // 获取互斥锁,保护共享资源
if(product>0) {
product--; // 产品数减1
}
std::cout << "消费者:产品数为:" << product << std::endl; // 输出当前产品数
pthread_mutex_unlock(&mutex); // 释放互斥锁
sem_post(&producer); // 释放生产者生产权限
sleep(2); // 消费后休眠2秒
}
return NULL; // 返回空指针,表示线程正常结束
}
// 主函数
int main(void) {
pthread_t m[3], n[3]; // 定义三个生产者和三个消费者的线程ID数组
pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
sem_init(&producer, 0, 3); // 初始化生产者信号量,初始值为3,表示允许同时有3个生产者工作
sem_init(&consumer, 0, 3); // 初始化消费者信号量,初始值为3,表示允许同时有3个消费者工作
// 创建三个生产者线程并开始运行
for (int i = 0; i < 3; i++) {
pthread_create(&m[i], NULL, Producer, NULL);
}
// 创建三个消费者线程并开始运行
for (int i = 0; i < 3; i++) {
pthread_create(&n[i], NULL, Consumer, NULL);
}
// 等待所有消费者线程结束
for (int i = 0; i < 3; i++) {
pthread_join(n[i], NULL);
}
// 等待所有生产者线程结束
for (int i = 0; i < 3; i++) {
pthread_join(m[i], NULL);
}
pthread_mutex_destroy(&mutex); // 销毁互斥锁对象,释放相关资源
sem_destroy(&producer); // 销毁生产者信号量对象,释放相关资源
sem_destroy(&consumer); // 销毁消费者信号量对象,释放相关资源
return 0; // 主函数返回0,表示程序正常结束
}
运行得到下面结果:
可以看到,通过信号量函数成功完成了生产者-消费者模型.值得注意的是,sem_wait函数应该出现在pthread_mutex_lock函数之前使用,否则可能会出现死锁现象.