C语言队列操作及其安全问题
在C语言中,队列是一种常用的数据结构,特别适用于嵌入式开发中的任务调度、缓冲区管理等场景。下面是一个简单的循环队列的模板代码,它使用数组来实现队列,并提供了基本的入队(enqueue)和出队(dequeue)操作。
示例代码如下:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#define QUEUE_MAX_SIZE 10 // 定义队列的最大容量
// 队列的结构体定义
typedef struct {
int data[QUEUE_MAX_SIZE]; // 存储队列元素的数组(如果需要动态扩展队列容量,可以考虑使用链表来实现队列)
int front; // 队列头部的索引
int rear; // 队列尾部的索引
} Queue;
// 初始化队列
void queueInit(Queue *q) {
q->front = q->rear = 0;
}
// 判断队列是否为空
bool isQueueEmpty(Queue *q) {
return q->front == q->rear;
}
// 判断队列是否已满
bool isQueueFull(Queue *q) {
return (q->rear + 1) % QUEUE_MAX_SIZE == q->front;
}
// 入队操作
bool enqueue(Queue *q, int value) {
if (isQueueFull(q)) {
return false; // 队列已满,无法入队
}
q->data[q->rear] = value;
q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;
return true;
}
// 出队操作
bool dequeue(Queue *q, int *value) {
if (isQueueEmpty(q)) {
return false; // 队列为空,无法出队
}
*value = q->data[q->front];
q->front = (q->front + 1) % QUEUE_MAX_SIZE;
return true;
}
// 打印队列中的所有元素
void printQueue(Queue *q) {
int i = q->front;
for (int count = 0; count < (q->rear - q->front + QUEUE_MAX_SIZE) % QUEUE_MAX_SIZE; count++) {
printf("%d ", q->data[i]);
i = (i + 1) % QUEUE_MAX_SIZE;
}
printf("\n");
}
// 主函数,演示队列的使用
int main() {
Queue q;
queueInit(&q);
// 入队操作
enqueue(&q, 1);
enqueue(&q, 2);
enqueue(&q, 3);
// 打印队列
printf("Queue after enqueue: ");
printQueue(&q);
// 出队操作
int value;
dequeue(&q, &value);
printf("Dequeued value: %d\n", value);
// 再次打印队列
printf("Queue after dequeue: ");
printQueue(&q);
return 0;
}
这段代码定义了一个队列结构体,包括一个整型数组来存储队列元素,以及两个索引来分别表示队列的头部和尾部。 enqueue 函数用于在队列尾部添加元素, dequeue 函数用于从队列头部移除元素。 isQueueEmpty 和 isQueueFull 函数分别用于检查队列是否为空或满。
但是,这个队列实现是线程不安全的。在多线程环境中使用时,需要添加适当的同步机制来避免竞态条件。
考虑引入同步机制,帮助解决上述队列实现中的不安全问题:
1.互斥锁(Mutex): 互斥锁是一种基本的同步机制,用于保护共享资源不被多个线程同时访问。在队列操作中,可以在入队和出队操作前后使用互斥锁来确保每次只有一个线程可以修改队列。
#include <pthread.h>
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
bool enqueue(Queue *q, int value) {
pthread_mutex_lock(&queue_mutex);
if (isQueueFull(q)) {
pthread_mutex_unlock(&queue_mutex);
return false;
}
q->data[q->rear] = value;
q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;
pthread_mutex_unlock(&queue_mutex);
return true;
}
bool dequeue(Queue *q, int *value) {
pthread_mutex_lock(&queue_mutex);
if (isQueueEmpty(q)) {
pthread_mutex_unlock(&queue_mutex);
return false;
}
*value = q->data[q->front];
q->front = (q->front + 1) % QUEUE_MAX_SIZE;
pthread_mutex_unlock(&queue_mutex);
return true;
}
2.条件变量(Condition Variable): 条件变量可以与互斥锁一起使用,以实现更高级的同步机制。它们允许线程在某些条件不满足时挂起,直到其他线程发出信号。
#include <pthread.h>
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t queue_not_full = PTHREAD_COND_INITIALIZER;
pthread_cond_t queue_not_empty = PTHREAD_COND_INITIALIZER;
bool enqueue(Queue *q, int value) {
pthread_mutex_lock(&queue_mutex);
while (isQueueFull(q)) {
pthread_cond_wait(&queue_not_full, &queue_mutex); // 等待队列有空间
}
q->data[q->rear] = value;
q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;
pthread_cond_signal(&queue_not_empty); // 通知可能有线程在等待出队
pthread_mutex_unlock(&queue_mutex);
return true;
}
bool dequeue(Queue *q, int *value) {
pthread_mutex_lock(&queue_mutex);
while (isQueueEmpty(q)) {
pthread_cond_wait(&queue_not_empty, &queue_mutex); // 等待队列中有元素
}
*value = q->data[q->front];
q->front = (q->front + 1) % QUEUE_MAX_SIZE;
pthread_cond_signal(&queue_not_full); // 通知可能有线程在等待入队
pthread_mutex_unlock(&queue_mutex);
return true;
}
3.读写锁(Read-Write Lock): 如果队列的读操作远多于写操作,使用读写锁可以提高性能。读写锁允许多个读操作同时进行,但写操作会独占锁。
#include <pthread.h>
pthread_rwlock_t queue_rwlock = PTHREAD_RWLOCK_INITIALIZER;
bool enqueue(Queue *q, int value) {
pthread_rwlock_wrlock(&queue_rwlock);
if (isQueueFull(q)) {
pthread_rwlock_unlock(&queue_rwlock);
return false;
}
// ... 入队操作
pthread_rwlock_unlock(&queue_rwlock);
return true;
}
bool dequeue(Queue *q, int *value) {
pthread_rwlock_wrlock(&queue_rwlock);
if (isQueueEmpty(q)) {
pthread_rwlock_unlock(&queue_rwlock);
return false;
}
// ... 出队操作
pthread_rwlock_unlock(&queue_rwlock);
return true;
}
void printQueue(Queue *q) {
pthread_rwlock_rdlock(&queue_rwlock);
// ... 打印队列操作
pthread_rwlock_unlock(&queue_rwlock);
}
4.原子操作: 某些编译器或硬件平台提供了原子操作,可以直接在不使用锁的情况下保证操作的原子性。这可以减少锁的开销,但通常只适用于简单的操作。
最后,需要注意,使用这些同步机制时,需要确保正确地初始化和销毁它们,并且在适当的时候获取和释放锁。同时,还需要考虑死锁的可能性,并采取相应的预防措施。
相关文章:
C语言队列操作及其安全问题
在C语言中,队列是一种常用的数据结构,特别适用于嵌入式开发中的任务调度、缓冲区管理等场景。下面是一个简单的循环队列的模板代码,它使用数组来实现队列,并提供了基本的入队(enqueue)和出队(de…...

next.js v14 升级全步骤|迁移 pages Router 到 App Router
【概括】本文升级整体按照官网文档指引进行,在迁移 pages Router 前先看了官网的实操视频。 【注意】文章内对 .babel.ts、next.config.js 进行了多次更改,最终配置可见 报错3: Server Error ReferenceError: React is not defined 一、升级 Next.js 版…...

如何在Ubuntu上安装WordPress
如何在Ubuntu上安装WordPress 执行系统更新 apt update && apt upgrade第一步 安装 Apache apt install apache2确认 Apache 安装是否成功. systemctl status apache2安装成功后 打开浏览器输入 http://server-ip-address 第二步 安装 MySQL apt install mariad…...
处理导入Excel文件过大导致Zip bomb detected的问题
处理导入Excel文件过大导致Zip bomb detected的问题 处理导入Excel文件过大导致Zip bomb detected的问题解决方案完整示例代码处理内存溢出问题优化处理大文件的策略 处理导入Excel文件过大导致Zip bomb detected的问题 在Java应用中导入Excel文件时,可能会遇到文件…...
【FFmpeg】AVIOContext结构体
【FFmpeg】AVIOContext结构体 1.AVIOContext结构体的定义 参考: FFMPEG结构体分析:AVIOContext 示例工程: 【FFmpeg】调用ffmpeg库实现264软编 【FFmpeg】调用ffmpeg库实现264软解 【FFmpeg】调用ffmpeg库进行RTMP推流和拉流 【FFmpeg】调用…...

Python控制结构
文章目录 控制结构1. 条件语句1.1 if语句1.2 elif语句1.3 else 语句 2. 循环语句2.1 for循环2.2 while循环 控制循环的语句3.1 break语句3.2 continue语句3.3 else语句与循环配合 控制结构 Python中的控制结构是指管理代码执行流程的语句和机制,包括条件语句、循环…...
OpenCV--图形轮廓
图形轮廓 图像轮廓查找轮廓绘制轮廓计算轮廓的面积和周长多边形逼近与凸包外接矩形 图像轮廓 import cv2 import numpy as np""" 图形轮廓--具有相同颜色或灰度的连续点的曲线 用于图形分析和物体的识别和检测 注意:为了检测的准确性,必…...
MYSQL通过EXPLAIN关键字来分析SQL查询的执行计划,判断是否命中了索引
在MySQL中,你可以通过EXPLAIN关键字来分析SQL查询的执行计划,从而判断是否命中了索引。 准备查询语句: 首先,你需要一个带有WHERE子句的SELECT查询,因为WHERE子句中的条件通常与索引相关联。例如: SELECT …...
clean code-代码整洁之道 阅读笔记(第十二章)
第十二章 系统 12.1 通过选进设计达到整洁目的 Kent Beck关于简单设计的四条规则,对于创建具有良好设计的软件有着莫大的帮助。 据Kent所述,只要遵循以下规则,设计就能变得"简单":运行所有测试;不可重复&…...
FFmpeg YUV编码为H264
使用FFmpeg库把YUV420P文件编码为H264文件,FFmpeg版本为4.4.2-0。 需要yuv测试文件的,可以从我上传的MP4文件中用ffmpeg提取,命令如下: ffmpeg -i <input.mp4> -pix_fmt yuv420p <output.yuv> 代码如下:…...

【C语言】顺序表(上卷)
什么是数据结构? 数据结构是由“数据”和“结构”两词组合而来的。 数据需要管理。数据结构就是计算机存储、组织数据的方式。比如一个班级就是一个结构,管理的就是班级里的学生。如果我们要找三年2班的同学李华,就可以直接去三年2班找而不…...

Luma AI如何注册:文生视频领域的新星
文章目录 Luma AI如何注册:文生视频领域的新星一、Luma 注册方式二、Luma 的效果三、Luma 的优势四、Luma 的功能总结 Luma AI如何注册:文生视频领域的新星 近年来,Luma AI 凭借其在文生视频领域的创新技术,逐渐成为行业的新星。…...

一站式实时数仓Hologres整体能力介绍
讲师:阿里云Hologres PD丁烨 一、产品定位 随着技术的进步,大数据正从规模化转向实时化处理。用户对传统的T1分析已不满足,期望获得更高时效性的计算和分析能力。例如实时大屏,城市大脑的交通监控、风控和实时的个性化推荐&…...
如何在 Windows 上安装 Docker Desktop
如何在 Windows 上安装 Docker Desktop Docker 是一个开放平台,用于开发、部署和运行应用程序。Docker Desktop 是 Docker 在 Windows 和 macOS 上的官方客户端,它使得开发者能够轻松地在本地环境中构建、运行和共享容器化应用程序。本文将详细介绍如何…...
WPF由文本框输入的内容动态渲染下拉框
在做项目过程中,需要扫码枪扫描快递单号或者手动输入快递单号时,自动检索该单号是哪个快递公司的,下拉框中自动带出该单号的快递公司。当输入的快递单号不存在时,将数据库中所有快递公司都带出 效果: 通过输入的快递单…...

RPCMon:一款基于ETW的RPC监控工具
关于RPCMon RPCMon是一款基于事件跟踪的WindowsRPC监控工具,该工具是一款GUI工具,可以帮助广大研究人员通过ETW(Event Tracing for Windows)扫描RPC通信。 RPCMon能够为广大研究人员提供进程之间RPC通信的高级视图,该…...

【odoo】常用的字符转义:“>“,“<“,““,“/“等
概要 字符转义是指在编写代码或处理文本数据时,将特殊字符转换为另一种形式,以便在特定的上下文中正确解析和处理这些字符。 内容 特殊字符描述XML转义表示法&和符号&<小于符号<>大于符号>"双引号"单引号&ap…...
李宏毅深度学习项目——HW1个人笔记
视频链接 PDF链接 googleColab链接 GoogleColab是一个免费的jupyter notebook,可以用上面的gpu资源进行训练 题目 通过前两天的数据,预测第三天某个人感染新冠的概率 范例 导包 # Numerical Operations import math import numpy as np# Reading/Wr…...

3D Gaussian Splatting Windows安装
0.安装C++ 编译器 https://aka.ms/vs/17/release/vs_buildtools.exe 1.下载源码 git clone https://github.com/graphdeco-inria/gaussian-splatting --recursive 2.安装cuda NVIDIA GPU Computing Toolkit CUDA Toolkit Archive | NVIDIA Developer 3.安装COLMAP...

人脸识别——可解释的人脸识别(XFR)人脸识别模型是根据什么来识别个人的
可解释性人脸识别(XFR)? 人脸识别有一个任务叫1:N(识别)。这个任务将一个人的照片与N张注册照片进行比较,找出相似度最高的人。 这项任务用于刑事调查和出入境点。在犯罪调查中,任务从监控摄像…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...