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

c语言多线程队列实现

为了用c语言实现队列进行多线程通信,用于实现一个状态机。
下面是实现过程

1.实现多线程队列入栈和出栈,不加锁

发送线程发送字符1,接收线程接收字符并打印。
多线程没有加锁,会有危险

#include "stdio.h"
#include <thread>
#include <unistd.h>
#include <pthread.h>typedef struct MutiThreadCharQueNode
{unsigned char data;struct MutiThreadCharQueNode* next;
}MutiThreadCharQueNode;typedef struct MutiThreadCharQueue
{MutiThreadCharQueNode* phead;MutiThreadCharQueNode* ptail;int size;
}MutiThreadCharQueue;
MutiThreadCharQueue TestMutiThreadQue;void MutiThreadCharQueueInit(MutiThreadCharQueue* pq)
{pq->phead=NULL; //将队列的头指针置为空pq->ptail = NULL;//将队列的尾指针置为空pq->size = 0;// 将队列的头指针置为空
}
bool MutiThreadCharQueueEmpty(MutiThreadCharQueue* pq)
{return pq->size == 0;
}
void MutiThreadCharQueueDestroy(MutiThreadCharQueue* pq)
{MutiThreadCharQueNode* cur = pq->phead;// 创建一个指针 cur,指向队列的头指针while (cur){MutiThreadCharQueNode* next = cur->next;// 创建一个指针 cur,指向队列的头指针free(cur);// 释放当前节点的内存cur = next;// 将指针 cur 移动到下一个节点}pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空pq->size = 0;// 将队列的大小置为0
}
void MutiThreadCharQueuePush(MutiThreadCharQueue* pq, unsigned char x)
{MutiThreadCharQueNode* newnode = (MutiThreadCharQueNode*)malloc(sizeof(MutiThreadCharQueNode));// 创建一个新的节点if (newnode == NULL){return;}newnode->data = x;// 设置新节点的数据为传入的元素值newnode->next = NULL;// 将新节点的指针域置空//一个节点if (pq->ptail == NULL)// 判断队列是否为空{pq->phead = pq->ptail = newnode;// 将新节点同时设置为队列的头节点和尾节点}//多个节点else{pq->ptail->next = newnode;// 将新节点同时设置为队列的头节点和尾节点pq->ptail = newnode;// 更新队列的尾指针为新节点}pq->size++;// 增加队列的大小计数
}
unsigned char MutiThreadCharQueueFront(MutiThreadCharQueue* pq)
{
//	assert(pq);// 检查指针是否为空
//	assert(!QueueEmpty(pq));// 检查队列是否非空
//	assert(pq->phead);// 检查队列的头指针是否存在
//    if(QueueEmpty(pq))
//    {
//        return ;
//    }return pq->phead->data;// 返回队列头节点的数据
}
void MutiThreadCharQueuePop(MutiThreadCharQueue* pq)
{//1.一个节点if (pq->phead->next == NULL) // 队列只有一个节点的情况{free(pq->phead); // 释放队列头节点的内存pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空}//2.多个节点else{MutiThreadCharQueNode* next = pq->phead->next; //保存队列头节点的下一个节点指针free(pq->phead);// 释放队列头节点的内存pq->phead = next;// 更新队列的头指针为下一个节点}pq->size--;//减少队列的大小计数
}
void* thread_send(void* para)
{printf("hh\n");MutiThreadCharQueueInit(&TestMutiThreadQue);unsigned char sendChar=1;while(1){printf("send a\n");MutiThreadCharQueuePush(&TestMutiThreadQue,sendChar);usleep(1000000);}
}
void* thread_rev(void* para)
{printf("h2\n");unsigned char revChar;while(1){if(false==MutiThreadCharQueueEmpty(&TestMutiThreadQue)){revChar=MutiThreadCharQueueFront(&TestMutiThreadQue);printf("rev char= %d\n",(int)revChar);MutiThreadCharQueuePop(&TestMutiThreadQue);}usleep(1000000);}
}void create_c_thread_send()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_send, (void*)NULL);}
void create_c_thread_rev()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_rev, (void*)NULL);}
int main(int argc, char** argv)
{printf("hello\n");create_c_thread_send();create_c_thread_rev();while(1){usleep(10000);}return 0;
}

2.实现多线程队列入栈和出栈,加锁并使用信号量触发接收线程

在队列的结构体中加上锁,防止多线程冲突

#include "stdio.h"
#include <thread>
#include <unistd.h>
#include <pthread.h>typedef struct MutiThreadCharQueNode
{unsigned char data;struct MutiThreadCharQueNode* next;
}MutiThreadCharQueNode;typedef struct MutiThreadCharQueue
{MutiThreadCharQueNode* phead;MutiThreadCharQueNode* ptail;int size;pthread_mutex_t mutex;
}MutiThreadCharQueue;
MutiThreadCharQueue TestMutiThreadQue;void MutiThreadCharQueueInit(MutiThreadCharQueue* pq)
{pq->phead=NULL; //将队列的头指针置为空pq->ptail = NULL;//将队列的尾指针置为空pq->size = 0;// 将队列的头指针置为空pthread_mutex_init(&pq->mutex, NULL);
}
bool MutiThreadCharQueueEmpty(MutiThreadCharQueue* pq)
{pthread_mutex_lock(&pq->mutex);bool bEmpty=(bool) (pq->size == 0);pthread_mutex_unlock(&pq->mutex);return bEmpty;
}
void MutiThreadCharQueueDestroy(MutiThreadCharQueue* pq)
{pthread_mutex_lock(&pq->mutex);MutiThreadCharQueNode* cur = pq->phead;// 创建一个指针 cur,指向队列的头指针while (cur){MutiThreadCharQueNode* next = cur->next;// 创建一个指针 cur,指向队列的头指针free(cur);// 释放当前节点的内存cur = next;// 将指针 cur 移动到下一个节点}pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空pq->size = 0;// 将队列的大小置为0pthread_mutex_unlock(&pq->mutex);
}
void MutiThreadCharQueuePush(MutiThreadCharQueue* pq, unsigned char x)
{pthread_mutex_lock(&pq->mutex);MutiThreadCharQueNode* newnode = (MutiThreadCharQueNode*)malloc(sizeof(MutiThreadCharQueNode));// 创建一个新的节点if (newnode == NULL){pthread_mutex_unlock(&pq->mutex);return;}newnode->data = x;// 设置新节点的数据为传入的元素值newnode->next = NULL;// 将新节点的指针域置空//一个节点if (pq->ptail == NULL)// 判断队列是否为空{pq->phead = pq->ptail = newnode;// 将新节点同时设置为队列的头节点和尾节点}//多个节点else{pq->ptail->next = newnode;// 将新节点同时设置为队列的头节点和尾节点pq->ptail = newnode;// 更新队列的尾指针为新节点}pq->size++;// 增加队列的大小计数pthread_mutex_unlock(&pq->mutex);
}
unsigned char MutiThreadCharQueueFront(MutiThreadCharQueue* pq)
{
//    if(QueueEmpty(pq))
//    {
//        return ;
//    }pthread_mutex_lock(&pq->mutex);char data=pq->phead->data;// 返回队列头节点的数据pthread_mutex_unlock(&pq->mutex);return data;
}
void MutiThreadCharQueuePop(MutiThreadCharQueue* pq)
{pthread_mutex_lock(&pq->mutex);//1.一个节点if (pq->phead->next == NULL) // 队列只有一个节点的情况{free(pq->phead); // 释放队列头节点的内存pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空}//2.多个节点else{MutiThreadCharQueNode* next = pq->phead->next; //保存队列头节点的下一个节点指针free(pq->phead);// 释放队列头节点的内存pq->phead = next;// 更新队列的头指针为下一个节点}pq->size--;//减少队列的大小计数pthread_mutex_unlock(&pq->mutex);
}
void* thread_send(void* para)
{printf("hh\n");MutiThreadCharQueueInit(&TestMutiThreadQue);unsigned char sendChar=1;while(1){printf("send a\n");MutiThreadCharQueuePush(&TestMutiThreadQue,sendChar);usleep(1000000);}
}
void* thread_rev(void* para)
{printf("h2\n");unsigned char revChar;while(1){if(false==MutiThreadCharQueueEmpty(&TestMutiThreadQue)){revChar=MutiThreadCharQueueFront(&TestMutiThreadQue);printf("rev char= %d\n",(int)revChar);MutiThreadCharQueuePop(&TestMutiThreadQue);}usleep(1000000);}
}void create_c_thread_send()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_send, (void*)NULL);}
void create_c_thread_rev()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_rev, (void*)NULL);}
int main(int argc, char** argv)
{printf("hello\n");create_c_thread_send();create_c_thread_rev();while(1){usleep(10000);}return 0;
}

3.实现任意数据类型的多线程队列

以上的队列数据类型固定了,希望实现一个通用的多线程队列,并且数据可以得到释放。

#include "stdio.h"
#include <thread>
#include <unistd.h>
#include <pthread.h>
#include <string.h>typedef struct MutiThreadQueNode
{void* data;struct MutiThreadQueNode* next;
}MutiThreadQueNode;typedef struct MutiThreadQueue
{MutiThreadQueNode* phead;MutiThreadQueNode* ptail;int size;int data_mem_size;pthread_mutex_t mutex;
}MutiThreadQueue;typedef struct TestMyStructData
{int my_int_data;float my_float_data;
}TestMyStructData;MutiThreadQueue TestMutiThreadQue;void MutiThreadQueueInit(MutiThreadQueue* pq,int data_mem_size)
{pq->phead=NULL; //将队列的头指针置为空pq->ptail = NULL;//将队列的尾指针置为空pq->size = 0;// 将队列的头指针置为空pq->data_mem_size=data_mem_size;pthread_mutex_init(&pq->mutex, NULL);
}
bool MutiThreadQueueEmpty(MutiThreadQueue* pq)
{pthread_mutex_lock(&pq->mutex);bool bEmpty=(bool) (pq->size == 0);pthread_mutex_unlock(&pq->mutex);return bEmpty;
}
void MutiThreadQueueDestroy(MutiThreadQueue* pq)
{pthread_mutex_lock(&pq->mutex);MutiThreadQueNode* cur = pq->phead;// 创建一个指针 cur,指向队列的头指针while (cur){MutiThreadQueNode* next = cur->next;// 创建一个指针 cur,指向队列的头指针//!由于data是拷贝过来的,释放data内存free(cur->data);free(cur);// 释放当前节点的内存cur = next;// 将指针 cur 移动到下一个节点}pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空pq->size = 0;// 将队列的大小置为0pthread_mutex_unlock(&pq->mutex);
}
void MutiThreadQueuePush(MutiThreadQueue* pq, void* data,int data_mem_size)
{pthread_mutex_lock(&pq->mutex);MutiThreadQueNode* newnode = (MutiThreadQueNode*)malloc(sizeof(MutiThreadQueNode));// 创建一个新的节点if (newnode == NULL){pthread_mutex_unlock(&pq->mutex);return;}if(pq->data_mem_size!=data_mem_size){printf("input data error\n");pthread_mutex_unlock(&pq->mutex);return;}void* queData=malloc(pq->data_mem_size);memcpy(queData,data,pq->data_mem_size);newnode->data = queData;// 设置新节点的数据为传入的元素值newnode->next = NULL;// 将新节点的指针域置空//一个节点if (pq->ptail == NULL)// 判断队列是否为空{pq->phead = pq->ptail = newnode;// 将新节点同时设置为队列的头节点和尾节点}//多个节点else{pq->ptail->next = newnode;// 将新节点同时设置为队列的头节点和尾节点pq->ptail = newnode;// 更新队列的尾指针为新节点}pq->size++;// 增加队列的大小计数pthread_mutex_unlock(&pq->mutex);
}
void MutiThreadQueueFront(MutiThreadQueue* pq,void* outData,int data_mem_size)
{
//    if(QueueEmpty(pq))
//    {
//        return ;
//    }pthread_mutex_lock(&pq->mutex);if(data_mem_size!=pq->data_mem_size){printf("input data_mem_size error\n");pthread_mutex_unlock(&pq->mutex);return ;}memcpy(outData,pq->phead->data,pq->data_mem_size);pthread_mutex_unlock(&pq->mutex);}
void MutiThreadQueuePop(MutiThreadQueue* pq)
{pthread_mutex_lock(&pq->mutex);//1.一个节点if (pq->phead->next == NULL) // 队列只有一个节点的情况{free(pq->phead); // 释放队列头节点的内存pq->phead = pq->ptail = NULL;// 将队列的头指针和尾指针置为空}//2.多个节点else{MutiThreadQueNode* next = pq->phead->next; //保存队列头节点的下一个节点指针//!由于data是拷贝过来的,释放data内存free(pq->phead->data);free(pq->phead);// 释放队列头节点的内存pq->phead = next;// 更新队列的头指针为下一个节点}pq->size--;//减少队列的大小计数pthread_mutex_unlock(&pq->mutex);
}
void* thread_send(void* para)
{printf("hh\n");TestMyStructData mySendData;mySendData.my_int_data=1;mySendData.my_float_data=2;MutiThreadQueueInit(&TestMutiThreadQue,sizeof(TestMyStructData));while(1){printf("send 1\n");MutiThreadQueuePush(&TestMutiThreadQue,&mySendData,sizeof(TestMyStructData));usleep(1000000);}
}
void* thread_rev(void* para)
{printf("h2\n");TestMyStructData myRevData;while(1){if(false==MutiThreadQueueEmpty(&TestMutiThreadQue)){MutiThreadQueueFront(&TestMutiThreadQue,&myRevData,sizeof(TestMyStructData));printf("rev intdata= %d float data=%f\n",myRevData.my_int_data,myRevData.my_float_data);MutiThreadQueuePop(&TestMutiThreadQue);}usleep(1000000);}
}void create_c_thread_send()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_send, (void*)NULL);}
void create_c_thread_rev()
{int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if (ret != 0) {return ;}//2pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int err;pthread_t tid;err = pthread_create(&tid, &attr, thread_rev, (void*)NULL);}
int main(int argc, char** argv)
{printf("hello\n");create_c_thread_send();create_c_thread_rev();while(1){usleep(10000);}return 0;
}

4.队列其他操作

队列操作可以完善的点
1.加上队列最大限制,如果队列内数据大小超过阈值,清空队列

相关文章:

c语言多线程队列实现

为了用c语言实现队列进行多线程通信&#xff0c;用于实现一个状态机。 下面是实现过程 1.实现多线程队列入栈和出栈&#xff0c;不加锁 发送线程发送字符1&#xff0c;接收线程接收字符并打印。 多线程没有加锁&#xff0c;会有危险 #include "stdio.h" #include …...

一分钟带你了解电容

电容器中的电容究竟是怎么定义的&#xff1f; 一个电容器&#xff0c;如果带1库的电量时两级间的电势差是1伏&#xff0c;这个电容器的电容就是1法拉&#xff0c;即&#xff1a;CQ/U 。但电容的大小不是由Q&#xff08;带电量&#xff09;或U&#xff08;电压&#xff09;决定…...

SQLAlchemy 第一篇

安装SQLAlchemy pip install SQLAlchemy查看当前版本 # 查看当前版本import sqlalchemyprint(sqlalchemy.__version__)2.0.23创建数据库连接 此处我们以pymysql为mysql的数据库驱动 安装pymysql pip install pymysqlfrom sqlalchemy import create_engine engine create_…...

Node.js模块化的基本概念和分类及使用方法

1.模块概念 模块&#xff1a;指解决一个复杂问题的时候&#xff0c;自顶向下逐层把系统划分成若干模块的过程。对于整个系统来讲&#xff0c;模块是可以组合、分解和更换的单元。 在编辑领域中的模块&#xff0c;就是遵守固定的规则&#xff0c;把一个大文件拆成独立并且相互…...

SpringBoot整合Lucene实现全文检索【详细步骤】【附源码】

笑小枫的专属目录 1. 项目背景2. 什么是Lucene3. 引入依赖&#xff0c;配置索引3.1 引入Lucene依赖和分词器依赖3.2 表结构和数据准备3.3 创建索引3.4 修改索引3.5删除索引 4. 数据检索4.1 基础搜索4.2 一个关键词&#xff0c;在多个字段里面搜索4.3 搜索结果高亮显示4.4 分页检…...

基于ssm生活缴费系统及相关安全技术的设计与实现论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对生活缴费信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…...

VS的python没有pandas(VS连接mysql数据库)

import pandas as pd from sqlalchemy import create_engine# 初始化数据库连接 engine create_engine(mysqlpymysql://root:556localhost:3306/仓库)sql_chaSELECT * FROM 库房 print(sql_cha) df_read pd.read_sql_query(sql_cha, engine); print(df_read);VS连接mysql如上…...

Java实现pdf文件合并

在maven项目中引入以下依赖包 <dependencies><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-examples</artifactId><version>3.0.1</version></dependency><dependency><groupId>co…...

ArcGIS导入excel中的经纬度信息,绘制矢量

1.首先整理坐标信息 2.其次转成2003格式的excel文件 3.导入arcgis&#xff0c;点击右键添加excel数据 4.显示xy数据 5.显示经度和纬度信息 6&#xff1a;点击【地理坐标系】->【World】->【WGS 1984】->【确定】 7.投影带的确定方式&#xff1a; 因为自己一直…...

【Hadoop】

Hadoop是一个开源的分布式离线数据处理框架&#xff0c;底层是用Java语言编写的&#xff0c;包含了HDFS、MapReduce、Yarn三大部分。 组件配置文件启动进程备注Hadoop HDFS需修改需启动 NameNode(NN)作为主节点 DataNode(DN)作为从节点 SecondaryNameNode(SNN)主节点辅助分…...

GitHub帐户管理更改电子邮件

登录到您的 GitHub 帐户&#xff1a; 前往 GitHub 网站并使用您的凭据登录。 访问个人设置&#xff1a; 单击右上角的您的头像&#xff0c;然后选择“Settings”&#xff08;设置&#xff09;。 选择电子邮件选项卡&#xff1a; 在左侧边栏中选择“Emails”&#xff08;电子邮…...

InsCode实践分享

一、背景介绍 随着社交媒体的普及&#xff0c;越来越多的品牌和商家开始关注如何利用社交媒体平台来提高品牌知名度和销售额。其中&#xff0c;Instagram作为一个以图片和视频为主要内容的社交媒体平台&#xff0c;已经成为了很多品牌和商家进行营销的重要渠道。InsCode是Inst…...

大一C语言作业 12.14

1.A A&#xff1a;将pa指向的元素赋值给x&#xff0c;即x a[0] B&#xff1a;将a数组第二个元素的值赋给x&#xff0c;即x a[1] C&#xff1a;将pa指向的下一个元素的值赋给x&#xff0c;即x a[1] D&#xff1a;将a数组第二个元素的值赋给x&#xff0c;即x a[1] 2. 6 2 3 …...

微服务技术 RabbitMQ SpringAMQP P61-P76

B站学习视频https://www.bilibili.com/video/BV1LQ4y127n4?p61&vd_source8665d6da33d4e2277ca40f03210fe53a 文档资料: 链接&#xff1a;https://pan.baidu.com/s/1P_Ag1BYiPaF52EI19A0YRw?pwdd03r 提取码&#xff1a;d03r 一 初始MQ 1. 同步通讯 2. 异步通讯 3. MQ常…...

BearPi Std 板从入门到放弃 - 先天神魂篇(3)(RT-Thread I2C设备 读取光照强度BH1750)

简介 使用BearPi IOT Std开发板及其扩展板E53_SC1&#xff0c; SC1上有I2C1 的光照强度传感器BH1750 和 EEPROM AT24C02&#xff0c; 本次主要就是读取光照强度; 主板: 主芯片: STM32L431RCT6LED : PC13 \ 推挽输出\ 高电平点亮串口: Usart1I2C使用 : I2C1E53_SC1扩展板 : LE…...

中文分词演进(查词典,hmm标注,无监督统计)新词发现

查词典和字标注 目前中文分词主要有两种思路&#xff1a;查词典和字标注。 首先&#xff0c;查词典的方法有&#xff1a;机械的最大匹配法、最少词数法&#xff0c;以及基于有向无环图的最大概率组合&#xff0c;还有基于语言模型的最大概率组合&#xff0c;等等。 查词典的方法…...

Docker容器数据卷

一、概念 1.定义 卷就是目录或文件&#xff0c;存在于一个或多个容器中&#xff0c;由docker挂载到容器&#xff0c;但不属于联合文件系统&#xff0c;因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。 卷的设计目的就是数据的持久化&#xff0c;完全独…...

chatGPT 国内版,嵌入midjourney AI创作工具

聊天GPT国内入口,免切网直达,可直接多语言对话,操作简单,无需复杂注册,智能高效,即刻使用.可以用作个人助理,学习助理,智能创作、新媒体文案创作、智能创作等各种应用场景! 地址&#xff1a; https://ai.wboat.cn/...

Yum仓库架构解析与搭建实践

1.Yum仓库搭建 1.1本地Yum仓库图解 1.2Linux本地仓库搭建 配置本地光盘镜像仓库 1&#xff09;挂载 [roothadoop101 ~]# mount -t iso996 /dev/cdrom/mnt 2&#xff09;查看 [rooothadoop101 ~] # df -h | |grep -i mnt /dev/sr0 4.6G 4.4G 3&#xf…...

ElementPlus中的分页逻辑与实现

ElementPlus中的分页逻辑与实现 分页是web开发中必不可少的组件&#xff0c;element团队提供了简洁美观的分页组件&#xff0c;配合table数据可以实现即插即用的分页效果。分页的实现可以分成两种&#xff0c;一是前端分页&#xff0c;二是后端分页。这两种分页分别适用于不同…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...