Linux多线程基础(6):信号量(实现简单的生产者-消费者模型)

发布时间:2024年01月11日

信号量是一种同步机制,用于控制多个线程或进程对共享资源的访问。信号量本质上是一个计数器,它记录了可用资源的数量。当线程或进程需要访问共享资源时,它首先会检查信号量的值。如果信号量的值大于0,表示有可用的资源,线程或进程会减少信号量的值并继续执行。如果信号量的值为0,表示没有可用的资源,线程或进程会被阻塞,直到信号量的值增加。

1.信号量函数定义

要使用信号量,需要了解以下几个函数:

(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。

?

2.举例(用信号量实现简单的生产者-消费者模型)

?老样子,通过用信号量实现简单的生产者-消费者模型说明这四个函数的用法.代码如下:

// 引入必要的头文件  
#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函数之前使用,否则可能会出现死锁现象.

文章来源:https://blog.csdn.net/shnhe/article/details/135426245
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。