【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;
}
二、共享内存
允许两个或多个进程共享一个给定的存储区,由于无需复制数据,这是最快的IPC进程间通信。
1.关联共享内存ftok
#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;
}
2.获取共享内存shmget
#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;
}
3.绑定共享内存shmat
#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;
}
4.绑定分离shmdt
#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
#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;
}
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;
}
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;
}
成功输出结果,前100项求和的结果为5050,但是当使用程序求前10000项和时,却会出现问题如图结果为50007661(错误结果)。
出现问题的原因是:执行中的进程没有保障,进程之间发生竞争(同一时刻多个进程对内存进行读写操作,发生在多核处理器)
可以利用条件变量实现线程同步机制(进程同步),从而避免资源抢占竞争。
四、非亲缘进程间通信
共享内存实现多进程计算,
- 单核不考虑同步关系,可以正常实现
- 多核不考虑同步关系,无法正常实现
- 需要设置同步关系
- 利用条件变量实现进程同步
非亲缘进程之间的通信,
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;
}
2.通过条件变量同步
思考:如何通过条件变量以及互斥锁,通过共享内存空间实现多进程同步
- 一个进程1号进程,作为主要发送进程
- 多个进程,输出1号进程发送的数据
- 利用条件变量和互斥锁实现同步
#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;
}
相关文章:
【Linux系统编程】06:共享内存
共享内存 OVERVIEW共享内存一、文件上锁flock二、共享内存1.关联共享内存ftok2.获取共享内存shmget3.绑定共享内存shmat4.绑定分离shmdt5.控制共享内存shmctl三、亲缘进程间通信1.共享内存写入与读取2.共享内存解绑与删除3.共享内存综合四、非亲缘进程间通信1.通过sleep同步2.通…...
【专项】112. 路径总和
112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点 …...
【数据结构】堆排序
堆是一种叫做完全二叉树的数据结构,可以分为大根堆,小根堆,而堆排序就是基于这种结构而产生的一种程序算法。大堆:每个节点的值都大于或者等于他的左右孩子节点的值小堆:每个结点的值都小于或等于其左孩子和右孩子结点…...
论文阅读笔记《GAMnet: Robust Feature Matching via Graph Adversarial-Matching Network》
核心思想 本文提出一种基于图对抗神经网络的图匹配算法(GAMnet),使用图神经网络作为生成器分别生成源图和目标图的节点的特征,并用一个多层感知机作为辨别器来区分两个特征是否来自同一个图,通过对抗训练的办法提高生成器特征提取…...
数据安全—数据完整性校验
1、数据安全保障三要素即 保密性 完整性、可用性机密性:要求数据不被他人轻易获取,需要进行数据加密。完整性:要求数据不被他人随意修改,需要进行签名技术可用性:要求服务不被他人恶意攻击,需要进行数据校验…...
Java 最小路径和
最小路径和中等给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。示例 1:输入:grid [[1,3,1],[1,5,1],[4,2,1]]输出&…...
Flask+VUE前后端分离的登入注册系统实现
首先Pycharm创建一个Flask项目: Flask连接数据库需要下载的包: pip install -U flask-cors pip install flask-sqlalchemy Flask 连接和操作Mysql数据库 - 王滚滚啊 - 博客园 (cnblogs.com) sqlAlchemy基本使用 - 简书 (jianshu.com) FlaskVue前后端分…...
【Go】用Go在命令行输出好看的表格
用Go在命令行输出好看的表格前言正文生成Table表头设置插入行表格标题自动标号单元格合并列合并行合并样式设置居中设置数字自动高亮标红完整Demo代码结语前言 最近在写一些运维小工具,比如批量进行ping包的工具,实现不困难,反正就是ping&am…...
怎么处理消息重发的问题?
消息队列在消息传递的过程中,如果出现传递失败的情况,发送方会重试,在重试的过程中,可能会产生重复的消息。 消息重复的情况必然存在 关于传递消息时能够提供的服务质量标准,MQTT协议给出了三种不同的标准࿱…...
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(自动存储管理)在数据库中是非常重要的组成部分,它可以为磁盘提供统一的存储管理、提高磁盘访问的性能和可用性、简化管理复杂度,从而为数据库的运行提供更好的支持。这里就为大家整理了墨天轮数据社区上一些ASM相关基础知识、…...
java对象的创建与内存分配机制
文章目录对象的创建与内存分配机制对象的创建类加载检查分配内存初始化零值设置对象头指向init方法其他:指针压缩对象内存分配对象在栈上分配对象在Eden区中分配大对象直接分配到老年代长期存活的对象进入老年代对象动态年龄判断老年代空间分配担保机制对象的内存回…...
本地存储localStorage、sessionStorage
目录 一、localStorage 二、sessionStorage 三、本地存储处理复杂数据 一、localStorage 介绍 (1)数据存储在用户浏览器中 (2)设置、读取方便、甚至页面刷新不会丢失数据 (3)容量较大,se…...
JavaSE: 网络编程
1.1 概述java程序员面对统一的网络编程环境B/S 架构 和 C/S架构1.2 网络通信的两个要素通信双方的地址:ip 端口号网络通信协议:TCP/IP协议(事实上的国际规则)、OSI模型(理想化)1.3 Inet Address本地回环地…...
计算机图形学09:二维观察之点的裁剪
作者:非妃是公主 专栏:《计算机图形学》 博客地址:https://blog.csdn.net/myf_666 个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、二维观察基本…...
2023Java 并发编程面试题
Java 并发编程 1、在 java 中守护线程和本地线程区别? java 中的线程分为两种:守护线程(Daemon)和用户线程(User)。任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon(boolon…...
CAD如何绘制A0/A1/A2/A3/A4图框?
在CAD制图时,设计师一般会使用企业的定制图框模板或者个人的特色图框模板,让设计方案更加标准化、规范化。对于新人设计师而言,完成CAD制图已经非常头疼了,图框的绘制更是手忙脚乱。那么是否有更加高效的方式来完成A0、A1、A2、A3…...
R 安装 “umap-learn“ python 包
首先需要在R中下载并读取reticulate包,该包提供了一系列R-Python的交互式命令由于之前在电脑中通过三个方式安装了Python:直接安装 Python 3.10安装Anaconda,携带3.9安装 Miniconda,又是另外一个版本的Python版本各不相同…...
测试同学如何快速开发测试平台?
转眼已经好几个月没有发表什么文章了,因为疫情原因,大家工作都不怎么顺利,没有什么心情。再者,最近一直在搞移动端精准测试的项目,有太多技术难点需要攻克。从各个网站上都找不到解决方案,只能不断地尝试&a…...
【程序员接口百宝箱】免费常用API接口
一、短信发送 短信的应用可以说是非常的广泛了,短信API也是当下非常热门的API~ 短信验证码:可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商,3秒可达,99.99%到达率,支持大容量高并发。…...
使数组和能被P整除[同余定理+同余定理变形]
同余定理同余定理变形前言一、使数组和能被P整除二、同余定理变形总结参考资料前言 同余定理非常经典,采用前缀和 map,当两个余数前缀和为一个值时,则中间一段子数组刚好对P整除。但是能否找到前面是否有一段子数组和可以对P整除呐…...
25k的Java开发常问的Synchronized问题有哪些?
前言:面试高频的Synchronized问题大多集中在应用场景、底层实现原理、锁的升级过程。 文章目录 Synchronized定义应用场景对象加锁实现原理JDK6以前JDK6版本及以后对象从无锁到偏向锁转化的过程(大概讲五分钟)轻量级锁升级的过程(大概讲五分钟)自旋锁策略(大概讲五分钟)…...
ES增量同步方案
1 基于业务代码嵌入式的增量同步方式在Java业务代码要修改业务数据的地方,增加调用写入ES数据的方法优点:1、实现方式简单,可控粒度高;2、不依赖第三方数据同步框架;3、数据库不用做特殊配置和部署;缺点&am…...
计算器--课后程序(Python程序开发案例教程-黑马程序员编著-第6章-课后作业)
实例1:计算器 计算器极大地提高了人们进行数字计算的效率与准确性,无论是超市的收银台,还是集市的小摊位,都能够看到计算器的身影。计算器最基本的功能是四则运算。本实例要求编写程序,实现计算器的四则运算功能。 实…...
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 论文地址:Squeeze-a…...
arcgispro3.1(账号登陆)
ArcGIS Pro 3.1 更新中文概览专注于 制图、GIS、Python前言:本次更新给了我两个惊喜,一个是本来 ArcMap 就有的功能,另一个明显是学习的 QGIS,嘿嘿,大家往下看吧。整理翻译了一下官方的 ArcGIS Pro 3.1 新特性更新概览…...
VB6换个思路解决微信下载文件只读的问题(含源码)
日期:2023年3月10日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方…...
Allegro如何知道组合操作命令的拼写
Allegro如何知道组合操作命令的拼写 前面介绍了如何知道单个操作命令的拼写,但如果是复合命令,就无法直观的通过命令来了解,如下图 Snap Pick to -Segment这个命令拼写是什么 如何知道,具体操作如下 点击File点击Script 出现Scripting窗口...
CDO高效处理气象数据
基础命令,只需要在终端输入命令按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. 说明: Qt当中的Qt Quick框架使用QML语言来快速搭建优美的界面,但是对于单纯做界面的设计人员并不是很友好,还要让界面设计人员去消耗时间成本学习QML语法。Qt Designer Studio软件就是为了解决这个问题而设计的,工作人员不需要…...
wordpress 忽略更新/seo搜索引擎优化步骤
种善因,结善缘,得善果。 在五台山上有一位老僧,每次我遇到困惑时,都会去找老僧开示,每次从老僧那里离开后,身上的霉运都会散去。 因为自己最近经常走霉运,经常遇到不顺心的事,所以…...
深圳做商城网站建设/登封网站关键词优化软件
问题描述 N个人围成一个圈, 从第一个人开始报数, 报到M的人出圈, 剩下的人继续从1开始报数, 报到M的人出圈;如此往复, 直到所有人出圈. 列表解决 def solution_list(n, m): """ 初始化一个长度为n的列表, 默认值为True. 当某个元素出圈时, 将其置为False. 循环迭…...
wordpress博客转发/站长工具樱花
单片机 数字电压表(TLC2543) 一、简述 使用并行ADC会限制系统I/O口的功能扩展,采用串行ADC比较适合那些低速采样而控制管脚又比较多的系统。 TLC2543是TI公司的12位串行模数转换器,由于是串行输入结构,能够节省51系列单片机I/O资源ÿ…...
音乐网站前端模板/怎么做电商
介绍 JavaCC是Java语言实现的一个语法分析器。 官网:https://javacc.java.net/ 参考 http://www.cnblogs.com/Gavin_Liu/archive/2009/03/07/1405029.html查看原文:http://surenpi.com/2015/10/22/javacc/...
个性网站建设网站/个人怎么做免费百度推广
原文链接:https://blog.csdn.net/tianyl_melodie/article/details/53424116 总结: ①在应用启动的时候,首先会创建一个进程process,然后创建ActivityThread这个对象。 ②根据我们之前学习的Handler,可以知道&#x…...
wordpress调整页面布局/石家庄网站建设seo
频繁更换服务器IP大多可以归结为两个原因,IP被封或更换服务器,前者相对更多。一般来说,一次或两次更换IP并不会有很大的影响,最多是流量部分减少或收录减少,但这些在短时间内都可以恢复。频繁更换服务器IP会对网站产生…...