【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%到达率,支持大容量高并发。…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
