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

【Linux系统编程】06:共享内存

共享内存


OVERVIEW

  • 共享内存
      • 一、文件上锁flock
      • 二、共享内存
        • 1.关联共享内存ftok
        • 2.获取共享内存shmget
        • 3.绑定共享内存shmat
        • 4.绑定分离shmdt
        • 5.控制共享内存shmctl
      • 三、亲缘进程间通信
        • 1.共享内存写入与读取
        • 2.共享内存解绑与删除
        • 3.共享内存综合
      • 四、非亲缘进程间通信
        • 1.通过sleep同步
        • 2.通过条件变量同步

一、文件上锁flock

可以利用flock系统调用实现,当有一个进程在文件中进程写入操作时,其他进程无法在该文件中进行写操作(只能进行读操作)。

  • 多进程实现前n项数求和(利用flock实现)
#include "head.h"struct data {int now;//中间结果int sum;//求和结果
};void getnum(struct data *d) {int fd;if ((fd = open(".data", O_RDONLY)) < 0) {perror("setopen");exit(1);}read(fd, (void *)d, sizeof(struct data));close(fd);
}void setnum(struct data *d) {int fd;if ((fd = open(".data", O_RDWR | O_CREAT, 0600)) < 0) {//只有文件的所属用户(当前的进程)有访问以及写的权限perror("getopen");exit(1);}write(fd, (void *)d, sizeof(struct data));close(fd);
}void doSum(struct data *d, int max, int i) {int fd_lock;//将lock标志给到某个文件上(.lock) 通过该文件判断进程是否有资格打开另一个被保护的文件(.data)if ((fd_lock = open(".lock", O_RDONLY)) < 0) {perror("lockopen");exit(1);}while (1) {//计算的过程需要上锁flock(fd_lock, LOCK_EX);//加锁(加锁后其他进程后面计算的语句将无法执行)getnum(d);//从.data取出上个结果if (d->now >= max) break;//判断 计算结果d->now++;d->sum += d->now;setnum(d);//将计算的结果放回.dataprintf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);flock(fd_lock, LOCK_UN);//为解锁}close(fd_lock);
}int main(int argc, char *argv[]) {//多进程实现求前n项和 同一时刻只有一个进程持有该文件//计算从0到n的和 m个进程//a.out -i -n nint opt;int ins = 1, max = 100;struct data d;d.now = 0;d.sum = 0;setnum(&d);while ((opt = getopt(argc, argv, "i:n:")) != -1) {switch (opt) {case 'i':ins = atoi(optarg);break;case 'n':max = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);exit(1);}}int i;pid_t pid;for (i = 0; i < ins; ++i) {//创建ins个进程对文件进行doSum操作if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;}if (pid == 0) {doSum(&d, max, i);} else {for (int k = 0; k < ins; ++k) wait(NULL);}return 0;
}

image-20230224210120883

二、共享内存

允许两个或多个进程共享一个给定的存储区,由于无需复制数据,这是最快的IPC进程间通信。

1.关联共享内存ftok

image-20230224215755103

#include "head.h"int main() {//ftok将projectId与文件名字转换为键值对key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);printf("123 = 0x%x\n", 123);return 0;
}

image-20230224215900200

2.获取共享内存shmget

image-20230224212406973

#include "head.h"int main() {//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);return 0;
}

image-20230224221845280

3.绑定共享内存shmat

image-20230225230606913

#include "head.h"int main() {//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.将进程的动态内存空间和 共享内存空间关联void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}sleep(10);return 0;
}

image-20230225232517349

4.绑定分离shmdt

image-20230225232744715

#include "head.h"int main() {//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.将进程的动态内存空间和 共享内存空间关联void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}//4.将进程的动态内存空间和 共享内存空间关联解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}return 0;
}

5.控制共享内存shmctl

image-20230226002223768

#include "head.h"int main() {//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.将进程的动态内存空间和 共享内存空间关联void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}//4.将进程的动态内存空间和 共享内存空间关联解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}//5.shmctl删除共享内存空间if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {perror("shmctl");exit(1);}return 0;
}

三、亲缘进程间通信

1.共享内存写入与读取

#include "head.h"//共享内存综合运用
int main() {key_t key;int shmid;pid_t pid;char *shmemory = NULL;//1.开辟一块共享内存空间//(1)申请一块共享内存 将projectId与文件名字转换为 共享内存键值if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}//(2)根据共享内存对应的key值 和内存大小size 得到共享内存的标识符if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}//(3)将进程的动态内存空间和 共享内存空间关联if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {perror("shmat");exit(1);}//2.创建子进程 进行运算操作if ((pid = fork()) < 0) {perror("fork");exit(1);}if (pid) {//父进程写入while(1) {printf("i am the father : \n");scanf("%[^\n]s", shmemory);//向共享内存中写入getchar();//吞掉回车否则不停循环sleep(2);}} else {//子进程读出while (1) {sleep(1);if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);//如果共享内存空间中有数据才进行输出memset(shmemory, 0, 4096);//临时清空共享存储空间}}return 0;
}

image-20230228214143422

2.共享内存解绑与删除

#include "head.h"//共享内存综合运用
int main() {key_t key;int shmid;pid_t pid;char *shmemory = NULL;//1.开辟一块共享内存空间//(1)申请一块共享内存 将projectId与文件名字转换为 共享内存键值if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}//(2)根据共享内存对应的key值 和内存大小size 得到共享内存的标识符if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}//(3)将进程的动态内存空间和 共享内存空间关联if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {perror("shmat");exit(1);}//2.创建子进程 利用shmdt实现 一次读取一次读入操作if ((pid = fork()) < 0) {perror("fork");exit(1);}if (pid) {printf("i am the father : \n");scanf("%[^\n]s", shmemory);getchar();} else {sleep(5);if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);memset(shmemory, 0, 4096);}//3.删除开辟的共享内存空间//(1)将进程的动态内存空间和 共享内存空间关联解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}//(2)shmctl删除共享内存空间(父进程执行)if (pid) {wait(NULL);if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {perror("shmctl");exit(1);}}sleep(5);return 0;
}

image-20230228215903113

3.共享内存综合

  • 利用共享内存实现多进程前n项数求和(利用共享内存实现)
#include "head.h"struct data {int now;//中间结果int sum;//求和结果
};void doSum(struct data *d, int max, int i) {while (1) {//计算的过程需要上锁if (d->now >= max) break;//判断 计算结果d->now++;d->sum += d->now;printf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);}
}int main(int argc, char *argv[]) {//1.命令行解析 a.out -i -n nint opt;int ins = 1, max = 100;// struct data d;// d.now = 0;// d.sum = 0;// setnum(&d);while ((opt = getopt(argc, argv, "i:n:")) != -1) {switch (opt) {case 'i':ins = atoi(optarg);break;case 'n':max = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);exit(1);}}//2.共享内存的创建于绑定key_t key;int shmid;struct data *shmemory = NULL;//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值if ((key = ftok("5.shm_sum.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符if ((shmid = shmget(key, sizeof(struct data), IPC_CREAT | 0600)) < 0) {perror("shmget");exit(1);}//2.3将进程的动态内存空间和 共享内存空间关联if ((shmemory = (struct data *)shmat(shmid, NULL, 0)) == (struct data *)-1) {perror("shmat");exit(1);}shmemory->now = 0;shmemory->sum = 0;//3.创建ins个子进程对文件进行doSum操作int i;pid_t pid;for (i = 0; i < ins; ++i) {if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;}if (pid == 0) {doSum(shmemory, max, i);} else {for (int k = 0; k < ins; ++k) wait(NULL);printf("%d\n", shmemory->sum);}return 0;
}

image-20230228223341746

image-20230228223606341

成功输出结果,前100项求和的结果为5050,但是当使用程序求前10000项和时,却会出现问题如图结果为50007661(错误结果)。

image-20230228223444201

出现问题的原因是:执行中的进程没有保障,进程之间发生竞争(同一时刻多个进程对内存进行读写操作,发生在多核处理器)

可以利用条件变量实现线程同步机制(进程同步),从而避免资源抢占竞争。

四、非亲缘进程间通信

共享内存实现多进程计算,

  1. 单核不考虑同步关系,可以正常实现
  2. 多核不考虑同步关系,无法正常实现
  3. 需要设置同步关系
  4. 利用条件变量实现进程同步

非亲缘进程之间的通信,

1.通过sleep同步

  • 使用共享内存实现两个非亲缘关系进程(1号进程、2号进程)进行通话
  • 1号进程只输出2号进程在共享内存中输入的数据
  • 2号进程只输出1号进程在共享内存中输入的数据
  • 同步(通过sleep实现同步)
#include "head.h"struct SHM {int flag;//SHM能否读写int type;//第几个进程char mesg[50];//输入的信息
};int main(int argc, char *argv[]) {//1.命令行解析 ./a.out -t 1|2 -m messageint opt;int type;char mesg[50];struct SHM *temp;//用于临时存放准备写入共享内存的数据if (argc != 5) {fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);exit(1);}while ((opt = getopt(argc, argv, "t:m:")) != -1) {switch (opt) {case 't':type = atoi(optarg);break;case 'm':strcpy(mesg, optarg);break;default:fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);exit(1);}}/***存在问题*为什么直接在switch中使用 temp->type = atoi(optarg); 会出现segmentfault呢?*必须使用临时变量 int type; 来转接数据才不会报错? */temp->type = type;strcpy(temp->mesg, mesg);//2.共享内存的创建与绑定key_t key;int shmid;struct SHM *shmemory = NULL;//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值if ((key = ftok("1.shm_my.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {if (errno == EEXIST) {//处理重复创建共享内存空间if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {perror("shmget1");exit(1);}printf("shmemory exist!");} else {perror("shmget2");exit(1);}}//2.3将进程的动态内存空间和 共享内存空间关联if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {perror("shmat");exit(1);}//3.实现非亲缘进程间通信shmemory->flag = 0;//初始状态为允许写入while (1) {if (!shmemory->flag) {printf("<Process%d> : i get shmemory\n", temp->type);sprintf(shmemory->mesg, "<Process%d> : <%s>", temp->type, temp->mesg);//向共享内存中写入内容shmemory->flag = 1;sleep(1);} else {printf("%s\n", shmemory->mesg);//从共享内存中读取 并输出内容shmemory->flag = 0;}}return 0;
}

image-20230301103041419

2.通过条件变量同步

思考:如何通过条件变量以及互斥锁,通过共享内存空间实现多进程同步

  • 一个进程1号进程,作为主要发送进程
  • 多个进程,输出1号进程发送的数据
  • 利用条件变量和互斥锁实现同步

image-20230301110138124

#include "head.h"struct SHM {int type;//第几个进程char mesg[50];//输入的信息pthread_mutex_t mutex;//互斥锁pthread_cond_t cond;//条件变量
};int main(int argc, char *argv[]) {//1.命令行解析 ./a.out -t 1|2int opt;int type;if (argc != 3) {fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);exit(1);}while ((opt = getopt(argc, argv, "t:")) != -1) {switch (opt) {case 't':type = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);exit(1);}}//2.共享内存的创建与绑定key_t key;int shmid;struct SHM *shmemory = NULL;//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值if ((key = ftok("2.shm_cond.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {if (errno == EEXIST) {//处理重复创建共享内存空间if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {perror("shmget1");exit(1);}printf("shmemory exist!\n");} else {perror("shmget2");exit(1);}}//2.3将进程的动态内存空间和 共享内存空间关联if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {perror("shmat");exit(1);}//3.实现非亲缘进程间通信if (type == 1) {//让1号进程初始化互斥锁和信号量 并设为共享pthread_mutexattr_t mutex;pthread_condattr_t cond;pthread_mutexattr_init(&mutex);pthread_condattr_init(&cond);pthread_mutexattr_setpshared(&mutex, 1);//设置为共享pthread_condattr_setpshared(&cond, 1);//设置为共享pthread_mutex_init(&shmemory->mutex, &mutex);//初始化锁pthread_cond_init(&shmemory->cond, &cond);//初始化条件}if (type == 1) {while (1) {printf("ok\n");scanf("%[^\n]s", shmemory->mesg); getchar();if (strlen(shmemory->mesg)) pthread_cond_signal(&shmemory->cond);//1号进程写入后通知其他进程}} else {while (1) {pthread_mutex_lock(&shmemory->mutex);//一旦有某个进程拿到了共享内存 则将共享内存上锁pthread_cond_wait(&shmemory->cond, &shmemory->mutex);//共享内存上锁后 等待1号进程写入完成的通知//if (strlen(shmemory->mesg)) printf("<Process%d> : %s\n", type, shmemory->mesg);//将共享内存中写入的数据输出memset(shmemory->mesg, 0, strlen(shmemory->mesg));//清空共享内存pthread_mutex_unlock(&shmemory->mutex);}}return 0;
}

image-20230301171032340

相关文章:

【Linux系统编程】06:共享内存

共享内存 OVERVIEW共享内存一、文件上锁flock二、共享内存1.关联共享内存ftok2.获取共享内存shmget3.绑定共享内存shmat4.绑定分离shmdt5.控制共享内存shmctl三、亲缘进程间通信1.共享内存写入与读取2.共享内存解绑与删除3.共享内存综合四、非亲缘进程间通信1.通过sleep同步2.通…...

【专项】112. 路径总和

112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 …...

【数据结构】堆排序

堆是一种叫做完全二叉树的数据结构&#xff0c;可以分为大根堆&#xff0c;小根堆&#xff0c;而堆排序就是基于这种结构而产生的一种程序算法。大堆&#xff1a;每个节点的值都大于或者等于他的左右孩子节点的值小堆&#xff1a;每个结点的值都小于或等于其左孩子和右孩子结点…...

论文阅读笔记《GAMnet: Robust Feature Matching via Graph Adversarial-Matching Network》

核心思想 本文提出一种基于图对抗神经网络的图匹配算法&#xff08;GAMnet&#xff09;,使用图神经网络作为生成器分别生成源图和目标图的节点的特征&#xff0c;并用一个多层感知机作为辨别器来区分两个特征是否来自同一个图&#xff0c;通过对抗训练的办法提高生成器特征提取…...

数据安全—数据完整性校验

1、数据安全保障三要素即 保密性 完整性、可用性机密性&#xff1a;要求数据不被他人轻易获取&#xff0c;需要进行数据加密。完整性&#xff1a;要求数据不被他人随意修改&#xff0c;需要进行签名技术可用性&#xff1a;要求服务不被他人恶意攻击&#xff0c;需要进行数据校验…...

Java 最小路径和

最小路径和中等给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。说明&#xff1a;每次只能向下或者向右移动一步。示例 1&#xff1a;输入&#xff1a;grid [[1,3,1],[1,5,1],[4,2,1]]输出&…...

Flask+VUE前后端分离的登入注册系统实现

首先Pycharm创建一个Flask项目&#xff1a; Flask连接数据库需要下载的包&#xff1a; pip install -U flask-cors pip install flask-sqlalchemy Flask 连接和操作Mysql数据库 - 王滚滚啊 - 博客园 (cnblogs.com) sqlAlchemy基本使用 - 简书 (jianshu.com) FlaskVue前后端分…...

【Go】用Go在命令行输出好看的表格

用Go在命令行输出好看的表格前言正文生成Table表头设置插入行表格标题自动标号单元格合并列合并行合并样式设置居中设置数字自动高亮标红完整Demo代码结语前言 最近在写一些运维小工具&#xff0c;比如批量进行ping包的工具&#xff0c;实现不困难&#xff0c;反正就是ping&am…...

怎么处理消息重发的问题?

消息队列在消息传递的过程中&#xff0c;如果出现传递失败的情况&#xff0c;发送方会重试&#xff0c;在重试的过程中&#xff0c;可能会产生重复的消息。 消息重复的情况必然存在 关于传递消息时能够提供的服务质量标准&#xff0c;MQTT协议给出了三种不同的标准&#xff1…...

JVM 运行时数据区(数据区组成表述,程序计数器,java虚拟机栈,本地方法栈)

JVM 运行时数据区JVM 运行时数据区3.1运行时的数据区组成概述3.1.1程度计数器3.1.2java虚拟机栈3.1.3本地方法栈3.1.4java堆3.1.5方法区3.2程序计数器3.3java虚拟机栈3.4本地方法栈JVM 运行时数据区 堆,方法区(元空间) 主要用来存放数据 是线程共享的. 程序计数器,本地方法栈…...

Oracle ASM磁盘组配置、日常运维、故障处理等操作资料汇总

ASM&#xff08;自动存储管理&#xff09;在数据库中是非常重要的组成部分&#xff0c;它可以为磁盘提供统一的存储管理、提高磁盘访问的性能和可用性、简化管理复杂度&#xff0c;从而为数据库的运行提供更好的支持。这里就为大家整理了墨天轮数据社区上一些ASM相关基础知识、…...

java对象的创建与内存分配机制

文章目录对象的创建与内存分配机制对象的创建类加载检查分配内存初始化零值设置对象头指向init方法其他&#xff1a;指针压缩对象内存分配对象在栈上分配对象在Eden区中分配大对象直接分配到老年代长期存活的对象进入老年代对象动态年龄判断老年代空间分配担保机制对象的内存回…...

本地存储localStorage、sessionStorage

目录 一、localStorage 二、sessionStorage 三、本地存储处理复杂数据 一、localStorage 介绍 &#xff08;1&#xff09;数据存储在用户浏览器中 &#xff08;2&#xff09;设置、读取方便、甚至页面刷新不会丢失数据 &#xff08;3&#xff09;容量较大&#xff0c;se…...

JavaSE: 网络编程

1.1 概述java程序员面对统一的网络编程环境B/S 架构 和 C/S架构1.2 网络通信的两个要素通信双方的地址&#xff1a;ip 端口号网络通信协议&#xff1a;TCP/IP协议&#xff08;事实上的国际规则&#xff09;、OSI模型&#xff08;理想化&#xff09;1.3 Inet Address本地回环地…...

计算机图形学09:二维观察之点的裁剪

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、二维观察基本…...

2023Java 并发编程面试题

Java 并发编程 1、在 java 中守护线程和本地线程区别&#xff1f; java 中的线程分为两种&#xff1a;守护线程&#xff08;Daemon&#xff09;和用户线程&#xff08;User&#xff09;。任何线程都可以设置为守护线程和用户线程&#xff0c;通过方法Thread.setDaemon(boolon…...

CAD如何绘制A0/A1/A2/A3/A4图框?

在CAD制图时&#xff0c;设计师一般会使用企业的定制图框模板或者个人的特色图框模板&#xff0c;让设计方案更加标准化、规范化。对于新人设计师而言&#xff0c;完成CAD制图已经非常头疼了&#xff0c;图框的绘制更是手忙脚乱。那么是否有更加高效的方式来完成A0、A1、A2、A3…...

R 安装 “umap-learn“ python 包

首先需要在R中下载并读取reticulate包&#xff0c;该包提供了一系列R-Python的交互式命令由于之前在电脑中通过三个方式安装了Python&#xff1a;直接安装 Python 3.10安装Anaconda&#xff0c;携带3.9安装 Miniconda&#xff0c;又是另外一个版本的Python版本各不相同&#xf…...

测试同学如何快速开发测试平台?

转眼已经好几个月没有发表什么文章了&#xff0c;因为疫情原因&#xff0c;大家工作都不怎么顺利&#xff0c;没有什么心情。再者&#xff0c;最近一直在搞移动端精准测试的项目&#xff0c;有太多技术难点需要攻克。从各个网站上都找不到解决方案&#xff0c;只能不断地尝试&a…...

【程序员接口百宝箱】免费常用API接口

一、短信发送 短信的应用可以说是非常的广泛了&#xff0c;短信API也是当下非常热门的API~ 短信验证码&#xff1a;可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商&#xff0c;3秒可达&#xff0c;99.99&#xff05;到达率&#xff0c;支持大容量高并发。…...

使数组和能被P整除[同余定理+同余定理变形]

同余定理同余定理变形前言一、使数组和能被P整除二、同余定理变形总结参考资料前言 同余定理非常经典&#xff0c;采用前缀和 map&#xff0c;当两个余数前缀和为一个值时&#xff0c;则中间一段子数组刚好对P整除。但是能否找到前面是否有一段子数组和可以对P整除呐&#xf…...

25k的Java开发常问的Synchronized问题有哪些?

前言:面试高频的Synchronized问题大多集中在应用场景、底层实现原理、锁的升级过程。 文章目录 Synchronized定义应用场景对象加锁实现原理JDK6以前JDK6版本及以后对象从无锁到偏向锁转化的过程(大概讲五分钟)轻量级锁升级的过程(大概讲五分钟)自旋锁策略(大概讲五分钟)…...

ES增量同步方案

1 基于业务代码嵌入式的增量同步方式在Java业务代码要修改业务数据的地方&#xff0c;增加调用写入ES数据的方法优点&#xff1a;1、实现方式简单&#xff0c;可控粒度高&#xff1b;2、不依赖第三方数据同步框架&#xff1b;3、数据库不用做特殊配置和部署&#xff1b;缺点&am…...

计算器--课后程序(Python程序开发案例教程-黑马程序员编著-第6章-课后作业)

实例1&#xff1a;计算器 计算器极大地提高了人们进行数字计算的效率与准确性&#xff0c;无论是超市的收银台&#xff0c;还是集市的小摊位&#xff0c;都能够看到计算器的身影。计算器最基本的功能是四则运算。本实例要求编写程序&#xff0c;实现计算器的四则运算功能。 实…...

YOLOv5中添加SE模块详解——原理+代码

目录一、SENet1. 设计原理2. SE Block2.1 Squeeze:Global Information Embedding2.2 Excitation:Adaptive Recalibration3. SE-Inception and SE-ResNet二、YOLOv5中添加SENet1.修改common.py2.修改yolo.py3.修改yolov5s.yaml参考文章一、SENet 论文地址&#xff1a;Squeeze-a…...

arcgispro3.1(账号登陆)

ArcGIS Pro 3.1 更新中文概览专注于 制图、GIS、Python前言&#xff1a;本次更新给了我两个惊喜&#xff0c;一个是本来 ArcMap 就有的功能&#xff0c;另一个明显是学习的 QGIS&#xff0c;嘿嘿&#xff0c;大家往下看吧。整理翻译了一下官方的 ArcGIS Pro 3.1 新特性更新概览…...

VB6换个思路解决微信下载文件只读的问题(含源码)

日期&#xff1a;2023年3月10日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…...

Allegro如何知道组合操作命令的拼写

Allegro如何知道组合操作命令的拼写 前面介绍了如何知道单个操作命令的拼写,但如果是复合命令,就无法直观的通过命令来了解,如下图 Snap Pick to -Segment这个命令拼写是什么 如何知道,具体操作如下 点击File点击Script 出现Scripting窗口...

CDO高效处理气象数据

基础命令&#xff0c;只需要在终端输入命令按enter运行即可 ####### 查看文件信息 cdo infos xxx.nc #显示nc文件中的变量名 cdo showname sst.nc #读文件夹下的数据 for i in $(ls);do echo processing $i ;done #线性插值 cdo remapbil,经度纬度 input.nc output.nc ;done ##…...

1. Qt Designer Studio界面介绍

1. 说明&#xff1a; Qt当中的Qt Quick框架使用QML语言来快速搭建优美的界面&#xff0c;但是对于单纯做界面的设计人员并不是很友好&#xff0c;还要让界面设计人员去消耗时间成本学习QML语法。Qt Designer Studio软件就是为了解决这个问题而设计的&#xff0c;工作人员不需要…...

elementUI+vue_vue-admin-template框架

目录安装版本管理文件mock文件夹---模拟数据permission.js --- 登录权限控制文件安装 克隆项目git clone https://gitee.com/panjiachen/vue-admin-template.git进入项目目录cd vue-element-admin安装依赖npm install启动服务npm run dev版本管理 由于我们之前的项目是直接从…...

SpringBoot项目使用Schedule注释创建定时任务

文章目录知识讲解相关注释&#xff08;主要两个,EnableScheduling和Scheduled&#xff09;scheduled的cron语法代码项目目录结构启动类&#xff08;Application&#xff09;定时任务类(Task)配置类&#xff08;application.properties&#xff09;pom依赖展望&#xff08;Quart…...

学习 Python 之 Pygame 开发魂斗罗(十一)

学习 Python 之 Pygame 开发魂斗罗&#xff08;十一&#xff09;继续编写魂斗罗1. 改写主类函数中的代码顺序2. 修改玩家初始化3. 显示玩家生命值4. 设置玩家碰到敌人死亡5. 设置敌人子弹击中玩家6. 修改updatePlayerPosition()函数逻辑继续编写魂斗罗 在上次的博客学习 Pytho…...

Linux驱动开发

一、驱动分类Linux中包含三大类驱动&#xff1a;字符设备驱动、块设备驱动和网络设备驱动。其中字符设备驱动是最大的一类驱动&#xff0c;因为字符设备最多&#xff0c;从led到I2C、SPI、音频等都属于字符设备驱动。块设备驱动和网络设备驱动都要比字符设备驱动复杂。因为其比…...

32--Vue-前端开发-Vue语法之组件化开发

一、vue语法回顾 购物车的例子 eg1:计算商品价格(掌握对象的迭代方法) <!DOCTYPE html> <html lang="en"> <head>...

打怪升级之CFileDialog类介绍

CFileDialog类 CFileDialog封装用于文件打开操作或文件保存操作的常见对话框。信息来源自Windows官方文档&#xff1a;https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cfiledialog-class?viewmsvc-170 这里重点介绍几个常用的函数功能&#xff1a; 构造函数 explic…...

配天智造自主原创数字工厂:百余名员工人均创收122万

配天智造&#xff08;832223&#xff09;2022年度报告显示&#xff0c;报告期内公司实现营业收入1.3亿元&#xff0c;同比增长52%&#xff0c;归属于挂牌公司股东的净利润3867万元&#xff0c;同比增长28.11%。而这家公司全部在职员工仅有107人&#xff0c;人均创收约为122万。…...

COLMAP

简介&#xff1a;在使用instant-ngp过程中需要使用COLMAP得到模型的必要输入&#xff0c;比如模型需要的相机外参我们就可以通过COLMAP中的sparse reconstruction稀疏重建得到&#xff1b;而对于depth map深度图我们则需要dense reconstruction稠密重建得到&#xff0c;下面我们…...

2023-3-8 刷题情况

礼盒的最大甜蜜度 题目描述 给你一个正整数数组 price &#xff0c;其中 price[i] 表示第 i 类糖果的价格&#xff0c;另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。 返回礼盒的 最大 甜蜜度。…...

关于长连接服务器和客户端之间要加入心跳的一些讨论

在之前的章节里深入浅出TCPIP之深入浅出TCPIP之TCP重传机制 我们都知道了TCPIP协议栈有个默认的TCP心跳机制,这个心跳机制是和socket绑定的,可以对指定的套接字开启协议栈的心跳检测机制。默认情况下,协议栈的心跳机制对socket套接字是关闭的,如果要使用需要人为开启的。 比…...

LeetCode——1590. 使数组和能被 P 整除

一、题目 给你一个正整数数组 nums&#xff0c;请你移除 最短 子数组&#xff08;可以为 空&#xff09;&#xff0c;使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度&#xff0c;如果无法满足题目要求&#xff0c;返回 -1…...

12N65-ASEMI高压MOS管12N65

编辑-Z 12N65在TO-220封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为0.68Ω&#xff0c;是一款N沟道高压MOS管。12N65的最大脉冲正向电流ISM为48A&#xff0c;零栅极电压漏极电流(IDSS)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。12N65功耗&#x…...

cushy-serial 一个轻量级Python serial库

本文自笔者博客: https://www.blog.zeeland.cn/archives/rgoihgxcoci3 简介 cushy-serial是一个轻量级的Serial框架&#xff0c;初衷是希望使Serial编程变得更加简单、快捷&#xff0c;因此&#xff0c;相较于传统的pyserial&#xff0c;该框架可以更加快速地构建起一个serial…...

音视频开发系列(7)——Opengl常用Api介绍part1

GLES20.glTexParameteri GLES20.glTexParameteri是OpenGL ES 2.0用于设置纹理过滤器和纹理包装模式的函数。它有三个参数&#xff1a; target参数 target参数指定要设置纹理参数的纹理目标&#xff0c;根据不同的target值&#xff0c;glTexParameteri函数的行为也会有所不同…...

linux时间的特殊用法

今天介绍linux下Date时间命令相关的特殊用法 date (当前的时间) 修改系统当前时间&#xff1a; date -s "2022-6-20 9:33:50" 昨天的时间是我们比较常用的&#xff1a; date -d "yesterday" %Y%m%d ( 昨天的时间) date -d "1 day ago" %Y%m%d …...

axios 封装,API接口统一管理

分享一个自己封装的 axios 网络请求 主要的功能及其优点&#xff1a; 将所有的接口放在一个文件夹中管理&#xff08;api.js&#xff09;。并且可以支持动态接口&#xff0c;就是 api.js 文件中定义的接口可以使用 :xx 占位&#xff0c;根据需要动态的改变。动态接口用法模仿…...

SpringBoot使用Redis实现缓存

目录 实现步骤 1. 在 pom.xml 配置文件中添加如下依赖 2. 在 application.properties 中添加如下配置 3. 新建 RedisConfig.class&#xff0c;继承 CachingConfigurerSupport&#xff0c;添加如下方法 4. 新建 RedisService.class 添加如下方法 注意&#xff1a;cacheKey…...

[失业前端恶补算法]JavaScript leetcode刷题top100(三)

专栏声明&#xff1a;只求用最简单的&#xff0c;容易理解的方法通过&#xff0c;不求优化&#xff0c;不喜勿喷 今天更新五个 easy 难度题目&#xff1a; 相交链表 题面 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个…...

Spark RDD的设计与运行原理

一、Spark RDD概念 一个RDD就是一个分布式对象集合&#xff0c;本质上是一个只读的分区记录集合&#xff0c;每个RDD可以分成多个分区&#xff0c;每个分区就是一个数据集片段&#xff0c;并且一个RDD的不同分区可以被保存到集群中不同的节点上&#xff0c;从而可以在集群中的…...

Golang的下载与安装

Windows系统 进入golang官方下载网站:所有版本 - Go 编程语言如图所示 下载后打开您下载的 MSI 文件,然后按照提示安装 Go。 验证是否已安装 Go。...