当前位置: 首页 > news >正文

信号量demo

原文地址:信号量demo – 无敌牛

欢迎参观我的博客网站:无敌牛 – 技术/著作/典籍/分享等

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


核心区别总结

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

关于条件变量的使用,参看往期文章:线程池pthread-pool – 无敌牛,在 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);           // 初始满槽位数 = 0sem_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;
}

编译测试:

http://www.dtcms.com/a/291126.html

相关文章:

  • 【华为机试】503. 下一个更大元素 II
  • 【华为机试】85. 最大矩形
  • Excel函数 —— UNIQUE 去重提取唯一值
  • 智能码表新革命:VTX316-TTS语音芯片如何重塑骑行体验
  • 【补充】Linux内核链表机制
  • C语言自定义类型:联合体和枚举
  • CS231n-2017 Lecture4神经网络笔记
  • 【爬虫】05 - 爬虫攻防
  • 车载软件架构 --- 软件开发面临的问题
  • 神经网络——归一化层
  • 从 C# 到 Python:项目实战第五天的飞跃
  • Ubuntu 22 集群部署 Apache Doris 3.0.3 笔记
  • 音视频重回顾及nat内网穿透相关再整理笔记
  • Ubuntu 22.04 安装 Docker (安装包形式)
  • ESP32-S3 小电视学习笔记1:分光棱镜、QMI8658六轴惯导计、1.3英寸LCD屏
  • 4.Java创建对象有几种方式?
  • Spring Cloud——Spring Cloud LoadBalancer
  • 7月21日总结
  • C/C++---emplace和emplace_back
  • 企业IT管理——IT系统灾难恢复计划及实施步骤参考模板
  • rk3588 Android 12 添加framework层服务,HAL库,从硬件驱动层到上层APP,实现led灯控
  • OpenAI开发的一款实验性大型语言模型(LLM),在2025年国际数学奥林匹克竞赛(IMO)中达到了金牌水平
  • 数智管理学(三十七)
  • liunx宝塔面板部署easyswoole项目
  • 常规笔记本和加固笔记本的区别
  • React 中使用immer修改state摆脱“不可变”
  • 打造自己的 Jar 文件分析工具:类名匹配 + 二进制搜索 + 日志输出全搞定
  • 从一开始的网络攻防(六):php反序列化
  • UART串口
  • 什么是内网穿透?本地内网无公网IP如何实现互联网上远程访问?