C语言练习【互斥锁、信号量线程同步、条件变量实现生产者消费者模型】

news2025/2/4 21:33:26

练习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(&not_full, &mutex);
        }

        // 生产数据并放入缓冲区
        buffer[in] = rand() % 100;
        printf("Producer %d produced: %d\n", id, buffer[in]);
        in = (in + 1) % BUFFER_SIZE;
        count++;

        // 通知消费者缓冲区有数据可以消费
        pthread_cond_signal(&not_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(&not_empty, &mutex);
        }

        // 消费数据
        int data = buffer[out];
        printf("Consumer consumed: %d\n", data);
        out = (out + 1) % BUFFER_SIZE;
        count--;

        // 通知生产者缓冲区有空间可以生产
        pthread_cond_signal(&not_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(&not_full, NULL);
    pthread_cond_init(&not_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(&not_full);
    pthread_cond_destroy(&not_empty);
    pthread_cond_destroy(&producer_cond);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2291989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

w190工作流程管理系统设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

linux下ollama更换模型路径

Linux下更换Ollama模型下载路径指南   在使用Ollama进行AI模型管理时&#xff0c;有时需要根据实际需求更改模型文件的存储路径。本文将详细介绍如何在Linux系统中更改Ollama模型的下载路径。 一、关闭Ollama服务   在更改模型路径之前&#xff0c;需要先停止Ollama服务。…

编程题-电话号码的字母组合(中等)

题目&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 解法一&#xff08;哈希表动态添加&#xff09;&#x…

浅谈《图解HTTP》

感悟 滑至尾页的那一刻&#xff0c;内心突兀的涌来一阵畅快的感觉。如果说从前对互联网只是懵懵懂懂&#xff0c;但此刻却觉得她是如此清晰而可爱的呈现在哪里。 介绍中说&#xff0c;《图解HTTP》适合作为第一本网络协议书。确实&#xff0c;它就像一座桥梁&#xff0c;连接…

架构知识整理与思考(其四)

书接上回 建议&#xff0c;没有看过上一章的可以看一下&#xff0c;上一章“架构知识整理与思考&#xff08;其二&#xff09;” 感觉这都成链表了。 三生万物 软件架构 终于&#xff0c;我们进入了具体的软件架构讨论中。 软件架构是什么&#xff1f;相关定义如下&#xf…

【C++】B2124 判断字符串是否为回文

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述输入格式&#xff1a;输出格式&#xff1a;样例&#xff1a; &#x1f4af;方法一&#xff1a;我的第一种做法思路代码实现解析 &#x1f4af;方法二&#xff1a;我…

基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级…

算法题(48):反转链表

审题&#xff1a; 需要我们将链表反转并返回头结点地址 思路&#xff1a; 一般在面试中&#xff0c;涉及链表的题会主要考察链表的指向改变&#xff0c;所以一般不会允许我们改变节点val值。 这里是单向链表&#xff0c;如果要把指向反过来则需要同时知道前中后三个节点&#x…

梯度、梯度下降、最小二乘法

在求解机器学习算法的模型参数&#xff0c;即无约束优化问题时&#xff0c;梯度下降是最常采用的方法之一&#xff0c;另一种常用的方法是最小二乘法。 1. 梯度和梯度下降 在微积分里面&#xff0c;对多元函数的参数求∂偏导数&#xff0c;把求得的各个参数的偏导数以向量的形式…

独立开发者小程序开发变现思路

随着移动互联网的发展&#xff0c;小程序已成为许多独立开发者展示才能和实现收入的重要平台。作为一种轻量级的应用形态&#xff0c;小程序具有开发成本低、用户体验好、传播效率高等优势&#xff0c;为独立开发者提供了多种变现方式。然而&#xff0c;要想实现真正的盈利&…

软件测试 - 概念篇

目录 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 [已解决]部署时连接超时附&#xff1a;Docker脚本Dockerfile创建镜像启动容器 1. 获取网易邮箱服务的授权码 温馨提示…

基于springboot+vue的航空散货调度系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

[MRCTF2020]Ez_bypass1(md5绕过)

[MRCTF2020]Ez_bypass1(md5绕过) ​​ 这道题就是要绕过md5强类型比较&#xff0c;但是本身又不相等&#xff1a; md5无法处理数组&#xff0c;如果传入的是数组进行md5加密&#xff0c;会直接放回NULL&#xff0c;两个NuLL相比较会等于true&#xff1b; 所以?id[]1&gg…

MATLAB实现多种群遗传算法

多种群遗传算法&#xff08;MPGA, Multi-Population Genetic Algorithm&#xff09;是一种改进的遗传算法&#xff0c;它通过将种群分成多个子种群并在不同的子种群之间进行交叉和交换&#xff0c;旨在提高全局搜索能力并避免早期收敛。下面是多种群遗传算法的主要步骤和流程&a…

强化学习笔记(5)——PPO

PPO视频课程来源 首先理解采样期望的转换 变量x在p(x)分布下&#xff0c;函数f(x)的期望 等于f(x)乘以对应出现概率p(x)的累加 经过转换后变成 x在q(x)分布下&#xff0c;f(x)*p(x)/q(x) 的期望。 起因是&#xff1a;求最大化回报的期望&#xff0c;所以对ceta求梯度 具体举例…

【MATLAB例程】TOA和AOA混合的高精度定位程序,适用于三维、N锚点的情况

代码实现了一个基于到达角&#xff08;AOA&#xff09;和到达时间&#xff08;TOA&#xff09;混合定位的例程。该算法能够根据不同基站接收到的信号信息&#xff0c;自适应地计算目标的位置&#xff0c;适用于多个基站的场景 文章目录 主要功能代码结构运行结果程序代码 主要功…

使用Pygame制作“青蛙过河”游戏

本篇博客将演示如何使用 Python Pygame 从零开始编写一款 Frogger 风格的小游戏。Frogger 是一款早期街机经典&#xff0c;玩家需要帮助青蛙穿越车水马龙的马路到达对岸。本示例提供了一个精简原型&#xff0c;包含角色移动、汽车生成与移动、碰撞检测、胜利条件等关键点。希望…

深度解读 Docker Swarm

一、引言 随着业务规模的不断扩大和应用复杂度的增加,容器集群管理的需求应运而生。如何有效地管理和调度大量的容器,确保应用的高可用性、弹性伸缩和资源的合理分配,成为了亟待解决的问题。Docker Swarm 作为 Docker 官方推出的容器集群管理工具,正是在这样的背景下崭露头…

8、面向对象:类、封装、构造方法

一、类 1、定义 类&#xff1a;对现实世界中事物的抽象。Student 对象&#xff1a;现实世界中具体的个体。张三、李四 这些具体的学生 面向对象的特征&#xff1a;抽象、封装、继承、多态 OOP: Object Oriented Programming&#xff08;面向对象编程&#xff09; 类和对象…