Linux 无名信号量(Semaphore)的使用

一、无名信号量的概念

Linux无名信号量(Semaphore)
  在Linux操作系统中,信号量(Semaphore)是一种用于进程间或线程间同步和互斥的工具。无名信号量(也被称为POSIX信号量)是POSIX标准的一部分,与System V信号量相比,它提供了更丰富的功能和更好的可移植性。
  无名信号量是一种用于控制多个线程进程对共享资源的访问的计数器。它通常用于实现两个功能。
同步:确保进程或线程以特定的顺序访问资源。
互斥:防止两个或多个进程或线程同时访问共享资源。
  信号量的值是一个非负整数,通常被称为“许可数”或“资源数”。当信号量的值为0时,表示没有资源可用;当信号量的值大于0时,表示有相应数量的资源可用。

二、无名信号量相关函数

无名信号量相关函数如下
sem_init():初始化一个无名信号量。
sem_destroy():销毁一个无名信号量。
sem_wait()(也称为sem_trywait()或sem_timedwait()):尝试减少信号量的值。如果信号量的值大于0,则将其减1并立即返回;如果信号量的值为0,则进程将被阻塞,直到信号量的值变为非零。
sem_post():增加信号量的值。这通常表示释放了一个资源。

头文件

#include <semaphore.h>

函数的详细内容,可查看手册,如 sem_wait() 函数,介绍如下:
在这里插入图片描述

三、信号量的使用步骤

使用信号量的步骤
①在程序全局区定义信号量;
②使用 sem_init()初始化信号量;
③ 使用 sem_wait()和 sem_post()对信号量进行 P/V 操作;
④ 使用 sem_destroy()销毁信号量。

四、应用场景

无名信号量在多线程编程和进程间通信(IPC)中非常有用。以下是一些可能的应用场景:
生产者-消费者问题:生产者生成数据项并将其放入缓冲区,而消费者从缓冲区中取出数据项并处理它们。使用信号量可以确保生产者在缓冲区满时不会写入数据,而消费者在缓冲区空时不会尝试读取数据。
读写锁:多个线程可以同时对共享资源进行读操作,但在写操作期间需要阻止其他线程进行读或写操作。信号量可以用于实现这种读写锁。

五、测试代码

  程序创建了一个生产者线程和一个消费者线程,线程间通过一个固定大小的缓冲区进行通信。生产者生产整数并将其放入缓冲区,而消费者从缓冲区中取出整数并打印。通过使用信号量empty和full,可以确保生产者不会在缓冲区满时写入数据,而消费者不会在缓冲区空时尝试读取数据。

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
#include <semaphore.h>  
  
#define BUFFER_SIZE 10  
  
int buffer[BUFFER_SIZE];  
int in = 0, out = 0;  
sem_t empty, full;  
  
void *producer(void *arg) {  
    for (int i = 0; i < 20; i++) {  
        sem_wait(&empty);  // 等待缓冲区有空位  
        buffer[in] = i;  
        printf("Producer produced %d\n", i);  
        in = (in + 1) % BUFFER_SIZE;  
        sem_post(&full);   // 表示缓冲区有一个新项  
    }  
    return NULL;  
}  
  
void *consumer(void *arg) {  
    for (int i = 0; i < 20; i++) {  
        sem_wait(&full);   // 等待缓冲区有项  
        int item = buffer[out];  
        printf("Consumer consumed %d\n", item);  
        out = (out + 1) % BUFFER_SIZE;  
        sem_post(&empty);  // 表示缓冲区有一个空位  
    }  
    return NULL;  
}  
  
int main() {  
    pthread_t p, c;  
    sem_init(&empty, 0, BUFFER_SIZE);  // 初始时缓冲区为空,有BUFFER_SIZE个空位  
    sem_init(&full, 0, 0);             // 初始时缓冲区无项  
  
    pthread_create(&p, NULL, producer, NULL);  
    pthread_create(&c, NULL, consumer, NULL);  
  
    pthread_join(p, NULL);  
    pthread_join(c, NULL);  
  
    sem_destroy(&empty);  
    sem_destroy(&full);  
  
    return 0;  
}

测试结果
在这里插入图片描述
线程中加入 sleep() 函数
在这里插入图片描述

代码如下:

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
#include <semaphore.h>  
#include <unistd.h>
  
#define BUFFER_SIZE 10  
  
int buffer[BUFFER_SIZE];  
int in = 0, out = 0;  
sem_t empty, full;  
  
void *producer(void *arg) {  
    for (int i = 0; i < 20; i++) {  
        sem_wait(&empty);  // 等待缓冲区有空位  
        buffer[in] = i;  
        printf("Producer produced %d\n", i);  
        in = (in + 1) % BUFFER_SIZE;  
        sem_post(&full);   // 表示缓冲区有一个新项  
        sleep(1);
    }  
    return NULL;  
}  
  
void *consumer(void *arg) {  
    for (int i = 0; i < 20; i++) {  
        sem_wait(&full);   // 等待缓冲区有项  
        int item = buffer[out];  
        printf("Consumer consumed %d\n", item);  
        out = (out + 1) % BUFFER_SIZE;  
        sem_post(&empty);  // 表示缓冲区有一个空位  
	sleep(1);
    }  
    return NULL;  
}  
  
int main() {  
    pthread_t p, c;  
    sem_init(&empty, 0, BUFFER_SIZE);  // 初始时缓冲区为空,有BUFFER_SIZE个空位  
    sem_init(&full, 0, 0);             // 初始时缓冲区无项  
  
    pthread_create(&p, NULL, producer, NULL);  
    pthread_create(&c, NULL, consumer, NULL);  
  
    pthread_join(p, NULL);  
    pthread_join(c, NULL);  
  
    sem_destroy(&empty);  
    sem_destroy(&full);  
  
    return 0;  
}

测试结果如下:
在这里插入图片描述
可以看到,第一种程序,因为没有sleep()让出 cpu,会一直生产数据,直到 empty 为空,也就是等待缓冲区空位为0 ,程序阻塞,让出 cpu ,消费者开始进行处理,直到 full 为空,处理完毕,让出 cpu。

  • 27
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值