共享内存和信号量

共享内存和信号量可以配合起来一起使用。

什么是共享内存?:

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。

共享内存中几个主要的api函数:

  1. shmget——创建/打开共享内存
  2. shmat——将共享内存与当前进程相关联
  3. shmdt——将当前进程与共享内存间脱离关联
  4. shmctl——操控共享内存

因为是共享一块内存,所以其中必然涉及到同步的问题。共享内存如何实现进程间的同步呢?也就是说不同的进程不能同时访问同一块内存》

这个时候就需要使用到信号量。

什么是信号量?

信号量 (Semaphore) 是一种用于进程间同步和互斥的机制,可以防止多个进程同时访问共享资源导致的数据不一致问题。

信号量主要有两种类型:

  • 计数信号量 (Counting Semaphore):用于控制对资源的计数,可以允许多个进程同时访问有限数量的资源。
  • 二进制信号量 (Binary Semaphore):类似于互斥锁,只能取0或1,通常用于实现互斥。

计数信号量主要用于解决生产者-消费者问题。而二进制信号量主要解决互斥的问题。

信号量的两个基本操作:

  • P (Proberen) 操作:也称为 "wait" 或 "down" 操作,尝试获取一个信号量。如果信号量大于0,则将信号量减1;如果信号量为0或负数,进程将进入等待状态,直到其他进程释放资源。
  • V (Verhogen) 操作:也称为 "signal" 或 "up" 操作,释放一个信号量,即将信号量加1。如果有进程在等待资源,则唤醒其中的一个进程。

信号量的实现步骤:

1.创建和初始化信号量
#include <semaphore.h>

sem_t semaphore; // 定义信号量

// 初始化信号量,0 表示在进程间共享,1 是信号量的初始值
sem_init(&semaphore, 0, 1);
2.使用P操作
// 等待信号量(P 操作)
sem_wait(&semaphore);
3.操作临界区数据
4.使用V操作
// 释放信号量(V 操作)
sem_post(&semaphore);
5.销毁信号量
sem_destroy(&semaphore);

两种信号量的解决的问题:

1.进程间互斥:

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>

sem_t semaphore;

void* write_to_file(void* arg) {
    sem_wait(&semaphore);  // P 操作,等待进入临界区
    // 临界区,写入文件
    printf("进程 %d 进入临界区,正在写入文件...\n", (int)arg);
    // 模拟文件写操作
    sleep(2);
    printf("进程 %d 退出临界区\n", (int)arg);
    sem_post(&semaphore);  // V 操作,释放信号量
    return NULL;
}

int main() {
    pthread_t t1, t2;
    sem_init(&semaphore, 0, 1);  // 初始化信号量

    pthread_create(&t1, NULL, write_to_file, (void*)1);
    pthread_create(&t2, NULL, write_to_file, (void*)2);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    sem_destroy(&semaphore);  // 销毁信号量
    return 0;
}

2. 生产者-消费者问题:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFER_SIZE 5

int buffer[BUFFER_SIZE];
int count = 0;

sem_t empty_slots;  // 表示空缓冲区的信号量
sem_t full_slots;   // 表示满缓冲区的信号量
sem_t mutex;        // 保护缓冲区访问的互斥信号量

void* producer(void* arg) {
    for (int i = 0; i < 10; ++i) {
        sem_wait(&empty_slots);  // 等待有空位
        sem_wait(&mutex);        // 进入临界区
        buffer[count++] = i;
        printf("生产者生产了数据 %d\n", i);
        sem_post(&mutex);        // 离开临界区
        sem_post(&full_slots);   // 通知有新数据
    }
    return NULL;
}

void* consumer(void* arg) {
    for (int i = 0; i < 10; ++i) {
        sem_wait(&full_slots);   // 等待有新数据
        sem_wait(&mutex);        // 进入临界区
        int data = buffer[--count];
        printf("消费者消费了数据 %d\n", data);
        sem_post(&mutex);        // 离开临界区
        sem_post(&empty_slots);  // 通知有空位
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;

    sem_init(&empty_slots, 0, BUFFER_SIZE);  // 初始为空位数
    sem_init(&full_slots, 0, 0);             // 初始为无满缓冲区
    sem_init(&mutex, 0, 1);                  // 互斥信号量

    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    sem_destroy(&empty_slots);
    sem_destroy(&full_slots);
    sem_destroy(&mutex);

    return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值