信号量demo

信号量demo

条件变量(Condition Variable)和信号量(Semaphore)是两种不同的同步原语,尽管它们都用于线程间协调,但设计目标、使用方式和适用场景有本质区别。以下是关键对比:


核心区别总结

特性条件变量 (Condition Variable)信号量 (Semaphore)
本质无状态,依赖外部条件判断有状态(整数计数器)
操作对象必须绑定一个互斥锁(Mutex)使用独立操作
唤醒机制需手动通知(notify自动释放(post 增加计数)
等待行为wait()释放锁并阻塞wait()(或 P()阻塞
典型用途等待特定条件成立(如“队列非空”)控制资源访问数量(如限流)

关于条件变量的使用,参看往期文章:https://www.madbull.site/?p=672,在 pthread_pool 项目中,主要是使用 条件变量 实现任务的处理,可以从这篇文章下载源码查看。


今天记录一下信号量的使用方法,代码如下:

// gcc sem.c -lpthread -o sem
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define BUFFER_SIZE 5  // 缓冲区大小
#define NUM_ITEMS 10   // 每个生产者生产的项目数量

// 共享缓冲区
int buffer[BUFFER_SIZE];
int in = 0;  // 生产者插入位置
int out = 0; // 消费者取出位置

// 信号量
sem_t empty;   // 空槽位信号量
sem_t full;    // 满槽位信号量
sem_t mutex;   // 互斥信号量(保护缓冲区)

// 生产者线程函数
void* producer(void* arg) {
    int producer_id = *((int*)arg);
    
    for (int i = 0; i < NUM_ITEMS; i++) {
        // 生产一个项目(模拟耗时)
        int item = rand() % 100;
        
        sem_wait(&empty);  // 等待空槽位(P操作)
        sem_wait(&mutex);  // 进入临界区(保护缓冲区)
        
        // 将项目放入缓冲区
        buffer[in] = item;
        printf("生产者 %d 生产: %d (位置: %d)\n", producer_id, item, in);
        in = (in + 1) % BUFFER_SIZE;
        
        sem_post(&mutex);  // 离开临界区
        sem_post(&full);   // 增加满槽位(V操作)
        
        usleep(rand() % 100000); // 随机睡眠
    }
    
    return NULL;
}

// 消费者线程函数
void* consumer(void* arg) {
    int consumer_id = *((int*)arg);
    
    for (int i = 0; i < NUM_ITEMS; i++) {
        sem_wait(&full);   // 等待满槽位(P操作)
        sem_wait(&mutex);  // 进入临界区(保护缓冲区)
        
        // 从缓冲区取出项目
        int item = buffer[out];
        printf("消费者 %d 消费: %d (位置: %d)\n", consumer_id, item, out);
        out = (out + 1) % BUFFER_SIZE;
        
        sem_post(&mutex);  // 离开临界区
        sem_post(&empty);  // 增加空槽位(V操作)
        
        // 消费项目(模拟耗时)
        usleep(rand() % 150000); // 随机睡眠
    }
    
    return NULL;
}

int main() {
    pthread_t prod_thread1, prod_thread2;
    pthread_t cons_thread1, cons_thread2;
    
    int prod_id1 = 1, prod_id2 = 2;
    int cons_id1 = 1, cons_id2 = 2;
    
    // 初始化信号量
    sem_init(&empty, 0, BUFFER_SIZE); // 初始空槽位数 = 缓冲区大小
    sem_init(&full, 0, 0);           // 初始满槽位数 = 0
    sem_init(&mutex, 0, 1);           // 互斥信号量初始为1(二进制信号量)
    
    // 创建生产者线程
    pthread_create(&prod_thread1, NULL, producer, &prod_id1);
    pthread_create(&prod_thread2, NULL, producer, &prod_id2);
    
    // 创建消费者线程
    pthread_create(&cons_thread1, NULL, consumer, &cons_id1);
    pthread_create(&cons_thread2, NULL, consumer, &cons_id2);
    
    // 等待线程结束
    pthread_join(prod_thread1, NULL);
    pthread_join(prod_thread2, NULL);
    pthread_join(cons_thread1, NULL);
    pthread_join(cons_thread2, NULL);
    
    // 销毁信号量
    sem_destroy(&empty);
    sem_destroy(&full);
    sem_destroy(&mutex);
    
    printf("所有生产和消费完成!\n");
    return 0;
}

编译测试:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注