C语言练习【互斥锁、信号量线程同步、条件变量实现生产者消费者模型】
练习1
请使用互斥锁 和 信号量分别实现5个线程之间的同步
互斥锁实现同步
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;//创建互斥锁
pthread_mutex_t m;
pthread_mutex_t m1;
pthread_mutex_t m2;
pthread_mutex_t m3;
pthread_mutex_t m4;void* thread_main1(void* arg)
{while(1){pthread_mutex_lock(&m1);printf("1#线程\n");sleep(1);pthread_mutex_unlock(&m2);}
}void* thread_main2(void* arg)
{while(1){pthread_mutex_lock(&m2);printf("2#线程\n");sleep(1);pthread_mutex_unlock(&m3);}
}void* thread_main3(void* arg)
{while(1){pthread_mutex_lock(&m3);printf("3#线程\n");sleep(1);pthread_mutex_unlock(&m4);}
}void* thread_main4(void* arg)
{while(1){pthread_mutex_lock(&m4);printf("4#线程\n");printf("-------------\n");sleep(1);pthread_mutex_unlock(&m);}
}int main(int argc, const char *argv[])
{//初始化互斥锁pthread_mutex_init(&m,NULL);pthread_mutex_init(&m1,NULL);pthread_mutex_init(&m2,NULL);pthread_mutex_init(&m3,NULL);pthread_mutex_init(&m4,NULL);pthread_mutex_lock(&m1);pthread_mutex_lock(&m2);pthread_mutex_lock(&m3);pthread_mutex_lock(&m4);//创建4个分支线程pthread_t id1;pthread_create(&id1,0,thread_main1,0);pthread_detach(id1);pthread_t id2;pthread_create(&id2,0,thread_main2,0);pthread_detach(id2);pthread_t id3;pthread_create(&id3,0,thread_main3,0);pthread_detach(id3);pthread_t id4;pthread_create(&id4,0,thread_main4,0);pthread_detach(id4);//主线程while(1){pthread_mutex_lock(&m);printf("主线程\n");sleep(1);pthread_mutex_unlock(&m1);}//销毁互斥锁pthread_mutex_destroy(&m);pthread_mutex_destroy(&m1);pthread_mutex_destroy(&m2);pthread_mutex_destroy(&m3);pthread_mutex_destroy(&m4);return 0;
}
信号量实现同步
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;//创建信号量
sem_t s;
sem_t s1;
sem_t s2;
sem_t s3;
sem_t s4;void* thread_main1(void* arg)
{while(1){sem_wait(&s1);printf("1#线程\n");sleep(1);sem_post(&s2);}
}void* thread_main2(void* arg)
{while(1){sem_wait(&s2);printf("2#线程\n");sleep(1);sem_post(&s3);}
}void* thread_main3(void* arg)
{while(1){sem_wait(&s3);printf("3#线程\n");sleep(1);sem_post(&s4);}
}void* thread_main4(void* arg)
{while(1){sem_wait(&s4);printf("4#线程\n");printf("----------------\n");sleep(1);sem_post(&s);}
}int main(int argc, const char *argv[])
{//初始化信号量sem_init(&s,0,1);sem_init(&s1,0,1);sem_init(&s2,0,1);sem_init(&s3,0,1);sem_init(&s4,0,1);sem_wait(&s1);sem_wait(&s2);sem_wait(&s3);sem_wait(&s4);//创建4个分支线程pthread_t id1;pthread_create(&id1,0,thread_main1,0);pthread_detach(id1);pthread_t id2;pthread_create(&id2,0,thread_main2,0);pthread_detach(id2);pthread_t id3;pthread_create(&id3,0,thread_main3,0);pthread_detach(id3);pthread_t id4;pthread_create(&id4,0,thread_main4,0);pthread_detach(id4);//销毁信号量sem_destroy(&s);sem_destroy(&s1);sem_destroy(&s2);sem_destroy(&s3);sem_destroy(&s4);//主线程while(1){sem_wait(&s);printf("主线程\n");sleep(1);sem_post(&s1);}return 0;
}
练习2
请使用条件变量实现2生产者2消费者模型,注意1个生产者在生产的时候,另外一个生产者不能生产
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>#define BUFFER_SIZE 5 // 缓冲区大小
#define NUM_PRODUCERS 2 // 生产者数量
#define NUM_CONSUMERS 2 // 消费者数量// 环形缓冲区
int buffer[BUFFER_SIZE];
int in = 0; // 下一个生产者放入数据的位置
int out = 0; // 下一个消费者取出数据的位置
int count = 0; // 当前缓冲区的元素个数pthread_mutex_t mutex; // 互斥锁
pthread_cond_t not_full; // 缓冲区不满时的条件变量
pthread_cond_t not_empty; // 缓冲区不空时的条件变量
pthread_cond_t producer_cond; // 控制生产者互斥的条件变量void *producer(void *arg) {int id = *((int *)arg);while (1) {sleep(rand() % 2); // 模拟生产时间pthread_mutex_lock(&mutex);// 确保每次只有一个生产者在生产if (id == 1) {pthread_cond_wait(&producer_cond, &mutex); // 如果是生产者2,等生产者1生产}// 等待缓冲区有空间while (count == BUFFER_SIZE) {pthread_cond_wait(¬_full, &mutex);}// 生产数据并放入缓冲区buffer[in] = rand() % 100;printf("Producer %d produced: %d\n", id, buffer[in]);in = (in + 1) % BUFFER_SIZE;count++;// 通知消费者缓冲区有数据可以消费pthread_cond_signal(¬_empty);// 唤醒另一个生产者if (id == 0) {pthread_cond_signal(&producer_cond); // 唤醒生产者2}pthread_mutex_unlock(&mutex);}return NULL;
}void *consumer(void *arg) {while (1) {sleep(rand() % 3); // 模拟消费时间pthread_mutex_lock(&mutex);// 等待缓冲区有数据while (count == 0) {pthread_cond_wait(¬_empty, &mutex);}// 消费数据int data = buffer[out];printf("Consumer consumed: %d\n", data);out = (out + 1) % BUFFER_SIZE;count--;// 通知生产者缓冲区有空间可以生产pthread_cond_signal(¬_full);pthread_mutex_unlock(&mutex);}return NULL;
}int main() {pthread_t producers[NUM_PRODUCERS], consumers[NUM_CONSUMERS];int ids[NUM_PRODUCERS] = {0, 1}; // 生产者的 ID// 初始化锁和条件变量pthread_mutex_init(&mutex, NULL);pthread_cond_init(¬_full, NULL);pthread_cond_init(¬_empty, NULL);pthread_cond_init(&producer_cond, NULL);// 创建生产者和消费者线程for (int i = 0; i < NUM_PRODUCERS; i++) {if (pthread_create(&producers[i], NULL, producer, (void *)&ids[i]) != 0) {perror("Producer thread creation failed");return 1;}}for (int i = 0; i < NUM_CONSUMERS; i++) {if (pthread_create(&consumers[i], NULL, consumer, NULL) != 0) {perror("Consumer thread creation failed");return 1;}}// 设置生产者1为启动生产的线程pthread_cond_signal(&producer_cond);// 等待所有线程结束for (int i = 0; i < NUM_PRODUCERS; i++) {pthread_join(producers[i], NULL);}for (int i = 0; i < NUM_CONSUMERS; i++) {pthread_join(consumers[i], NULL);}// 销毁锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(¬_full);pthread_cond_destroy(¬_empty);pthread_cond_destroy(&producer_cond);return 0;
}

相关文章:
C语言练习【互斥锁、信号量线程同步、条件变量实现生产者消费者模型】
练习1 请使用互斥锁 和 信号量分别实现5个线程之间的同步 互斥锁实现同步 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>…...
w190工作流程管理系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
linux下ollama更换模型路径
Linux下更换Ollama模型下载路径指南 在使用Ollama进行AI模型管理时,有时需要根据实际需求更改模型文件的存储路径。本文将详细介绍如何在Linux系统中更改Ollama模型的下载路径。 一、关闭Ollama服务 在更改模型路径之前,需要先停止Ollama服务。…...
编程题-电话号码的字母组合(中等)
题目: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 解法一(哈希表动态添加)&#x…...
浅谈《图解HTTP》
感悟 滑至尾页的那一刻,内心突兀的涌来一阵畅快的感觉。如果说从前对互联网只是懵懵懂懂,但此刻却觉得她是如此清晰而可爱的呈现在哪里。 介绍中说,《图解HTTP》适合作为第一本网络协议书。确实,它就像一座桥梁,连接…...
架构知识整理与思考(其四)
书接上回 建议,没有看过上一章的可以看一下,上一章“架构知识整理与思考(其二)” 感觉这都成链表了。 三生万物 软件架构 终于,我们进入了具体的软件架构讨论中。 软件架构是什么?相关定义如下…...
组合数:从基础理论到高效算法实现
文章目录 一、组合数学基础二、经典算法实现三、取模运算与高效算法四、算法选择策略五、典型应用场景六、进阶技巧七、常用模板总结: 一、组合数学基础 1.1 组合数定义 在离散数学中,组合数 C ( n , k ) C(n,k) C(n,k)(记为 ( n k ) \dbi…...
【C++】B2124 判断字符串是否为回文
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式:输出格式:样例: 💯方法一:我的第一种做法思路代码实现解析 💯方法二:我…...
DeepSpeed Zero 解读
目录 主要参考: 分布式训练基础 – 数据并行,模型并行,流水线并行 DeepSpeed Zero 的各个 stage 介绍 针对Zero 的各个stage,这里有三个点需要额外再说一下: 各个stage,要实现将某一部分参数分配到不同GPU,…...
Windows 安装Linux子系统
文章目录 一、启用虚拟化二、安装子系统1. 查看所有官方支持的 WSL 发行版2. 安装 Ubuntu3. 安装非官方发行版(如 CentOS)三、启动和更新子系统1. 启动Ubuntu终端2. 更新系统四、管理已安装的发行版在 Windows 的 WSL(Windows Subsystem for Linux)中,除了 Ubuntu,你还可…...
基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…...
【LeetCode 刷题】回溯算法(5)-棋盘问题
此博客为《代码随想录》二叉树章节的学习笔记,主要内容为回溯算法棋盘问题相关的题目解析。 文章目录 51. N皇后37. 解数独332.重新安排行程 51. N皇后 题目链接 class Solution:def solveNQueens(self, n: int) -> List[List[str]]:board [[. for _ in rang…...
PaddleOCR 截图自动文字识别
春节假期在家无聊,撸了三个小工具:PC截图编辑/PC录屏(用于meeting录屏)/PC截屏文字识别。因为感觉这三个小工具是工作中常常需要用到的,github上也有很多开源的,不过总有点或多或少的小问题,不利于自己的使用。脚本的编…...
算法题(48):反转链表
审题: 需要我们将链表反转并返回头结点地址 思路: 一般在面试中,涉及链表的题会主要考察链表的指向改变,所以一般不会允许我们改变节点val值。 这里是单向链表,如果要把指向反过来则需要同时知道前中后三个节点&#x…...
梯度、梯度下降、最小二乘法
在求解机器学习算法的模型参数,即无约束优化问题时,梯度下降是最常采用的方法之一,另一种常用的方法是最小二乘法。 1. 梯度和梯度下降 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式…...
独立开发者小程序开发变现思路
随着移动互联网的发展,小程序已成为许多独立开发者展示才能和实现收入的重要平台。作为一种轻量级的应用形态,小程序具有开发成本低、用户体验好、传播效率高等优势,为独立开发者提供了多种变现方式。然而,要想实现真正的盈利&…...
软件测试 - 概念篇
目录 1. 需求 1.1 用户需求 1.2 软件需求 2. 开发模型 2.1 软件的生命周期 2.2 常见开发模型 2.2.1 瀑布模型 2.2.2 螺旋模型 1. 需求 对于软件开发而言, 需求分为以下两种: 用户需求软件需求 1.1 用户需求 用户需求, 就是用户提出的需求, 没有经过合理的评估, 通常…...
使用SpringBoot发送邮件|解决了部署时连接超时的bug|网易163|2025
使用SpringBoot发送邮件 文章目录 使用SpringBoot发送邮件1. 获取网易邮箱服务的授权码2. 初始化项目maven部分web部分 3. 发送邮件填写配置EmailSendService [已解决]部署时连接超时附:Docker脚本Dockerfile创建镜像启动容器 1. 获取网易邮箱服务的授权码 温馨提示…...
基于springboot+vue的航空散货调度系统
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
自学习记录-编程语言的特点(持续记录)
我学习的顺序是C -> python -> C -> Java。在讲到某项语言的特点是,可能会时不时穿插其他语言的特点。 Java 1 注解Annotation Python中也有类似的Decorators。以下为AI学习了解到的: Java的Annotation是一种元数据(metadata)&a…...
[MRCTF2020]Ez_bypass1(md5绕过)
[MRCTF2020]Ez_bypass1(md5绕过) 这道题就是要绕过md5强类型比较,但是本身又不相等: md5无法处理数组,如果传入的是数组进行md5加密,会直接放回NULL,两个NuLL相比较会等于true; 所以?id[]1&gg…...
MATLAB实现多种群遗传算法
多种群遗传算法(MPGA, Multi-Population Genetic Algorithm)是一种改进的遗传算法,它通过将种群分成多个子种群并在不同的子种群之间进行交叉和交换,旨在提高全局搜索能力并避免早期收敛。下面是多种群遗传算法的主要步骤和流程&a…...
强化学习笔记(5)——PPO
PPO视频课程来源 首先理解采样期望的转换 变量x在p(x)分布下,函数f(x)的期望 等于f(x)乘以对应出现概率p(x)的累加 经过转换后变成 x在q(x)分布下,f(x)*p(x)/q(x) 的期望。 起因是:求最大化回报的期望,所以对ceta求梯度 具体举例…...
【MATLAB例程】TOA和AOA混合的高精度定位程序,适用于三维、N锚点的情况
代码实现了一个基于到达角(AOA)和到达时间(TOA)混合定位的例程。该算法能够根据不同基站接收到的信号信息,自适应地计算目标的位置,适用于多个基站的场景 文章目录 主要功能代码结构运行结果程序代码 主要功…...
使用Pygame制作“青蛙过河”游戏
本篇博客将演示如何使用 Python Pygame 从零开始编写一款 Frogger 风格的小游戏。Frogger 是一款早期街机经典,玩家需要帮助青蛙穿越车水马龙的马路到达对岸。本示例提供了一个精简原型,包含角色移动、汽车生成与移动、碰撞检测、胜利条件等关键点。希望…...
深度解读 Docker Swarm
一、引言 随着业务规模的不断扩大和应用复杂度的增加,容器集群管理的需求应运而生。如何有效地管理和调度大量的容器,确保应用的高可用性、弹性伸缩和资源的合理分配,成为了亟待解决的问题。Docker Swarm 作为 Docker 官方推出的容器集群管理工具,正是在这样的背景下崭露头…...
8、面向对象:类、封装、构造方法
一、类 1、定义 类:对现实世界中事物的抽象。Student 对象:现实世界中具体的个体。张三、李四 这些具体的学生 面向对象的特征:抽象、封装、继承、多态 OOP: Object Oriented Programming(面向对象编程) 类和对象…...
AI时代IT行业职业方向规划大纲
一、引言 AI时代的颠覆性影响 ChatGPT、Midjourney等生成式AI对传统工作模式的冲击 案例:AI编程助手(GitHub Copilot)改变开发者工作流程 核心问题:IT从业者如何避免被AI替代,并找到新机遇? 二、AI时代…...
STM32 旋转编码器
旋转编码器简介 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向 类型:机械触点式/霍尔传…...
大模型领域的Scaling Law的含义及作用
Scaling Law就像是一个“长大公式”,用来预测当一个东西(比如模型)变大(比如增加参数、数据量)时,它的性能(比如准确率)会怎么变化。 它能帮助我们提前知道,增加多少资源…...
