【Linux】system V共享内存 | 消息队列 | 信号量
🌠 作者:@阿亮joy.
🎆专栏:《学会Linux》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
目录
- 👉system V共享内存👈
- 共享内存的原理
- 对共享内存的认识
- 共享内存函数
- 👉system V消息队列(了解)👈
- 👉system V信号量👈
- 进程互斥
- 👉总结👈
👉system V共享内存👈
共享内存的原理
共享内存区是最快的 IPC 形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核。换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据,进程如果要读写,直接进行内存即的读和写接口。而之前学习的 pipe 和 fifo 都要通过 read 和 write 系统调用才能进行通信,原因就是管道的本质是文件,文件是内核中的一种数据结构,由操作系统维护(3 到 4 G的内核空间),用户无权进行直接访问,只能通过系统调用来进行访问。注:堆栈之间的共享内存属于用户空间,内核空间是 3 到 4 G 之间的 1 G 内存空间。
对共享内存的认识
- 共享内存不属于通信的任意一个进程,其属于操作系统,由操作系统所管理。
- 管道的本质是文件,操作系统已经有相应的内核数据结构来管理文件,因此不需要再去设计新的内核数据结构去管理管道。而共享内存是专门为了进程间通信而设计的,操作系统可能会有很多共享内存,那么操作系统就需要将这些共享内存管理起来。
- 管理的方式是先描述再组织,那么共享内存就等于共享内存块加上共享内存对应的内核数据结构。
- 对共享内存的修改包括对属性的修改和对内容的修改。
共享内存内核数据结构
struct shmid_ds
{struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */unsigned short shm_unused; /* compatibility */void *shm_unused2; /* ditto - used by DIPC */void *shm_unused3; /* unused */
};
共享内存函数
- shmget 函数的功能是创建或获取共享内存,需要指明共享内存的权限,失败时的返回值是 -1。
- ftok 函数的功能将 pathname 和 project id 经过一定的算法转化成 system V IPC key。pathname 必须存在,project id 不能为 0。失败时的返回值是 -1。
- shmat 函数的功能是将共享内存段连接到进程地址空间(建立页表映射关系)。第一个参数是共享内存的标识符 shmid;第二个参数是指定连接的地址,为 nullptr 时,则让操作系统指定连接到合适的地址上;第三个参数是 shmflg,它的两个可能取值是 SHM_RND 和 SHM_RDONLY。shmflg 等于 SHM_RDONLY 时,表示连接操作用来只读共享内存。成功返回一个指针,指向共享内存第一个字节;失败返回 (void*) -1。
- shmdt 函数的功能是将共享内存段与当前进程脱离。shmaddr 是由 shmat 函数所返回的指针,成功返回 0;失败返回 -1。注意:将共享内存段与当前进程脱离不等于删除共享内存段。
- shmctl 函数的功能是用于控制共享内存。shmid 是由 shmget 函数返回的共享内存标识符;cmd 是将要采取的动作(有三个可取值);buf 为指向一个保存着共享内存的模式状态和访问权限的数据结构,不关心共享内存的内核数据结果是,buf 可以设置为 nullptr。
注:当进程运行结束,进程创建的共享内存还会存在。这是因为 system V IPC 资源的生命周期是随着其内核的,其内核可以通过代码删除(上述的 shmctl 函数),也可以通过 ipcrm -m shmid 指令手动删除共享内存。使用 ipcs -m 指令可以查看操作系统中已经创建的共享内存。
- key 和 shmid 的区别:只有在创建共享内存时,使用到 key。大部分情况下,用户都是通过 shmid 来访问共享内存的。
客户端和服务端的模拟实现
# Makefile
.PHONY:all
all:shmClient shmServershmClient:shmClient.ccg++ -o $@ $^ -std=c++11
shmServer:shmServer.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f shmClient shmServer
// Log.hpp
#ifndef _LOG_H_
#define _LOG_H_#include <iostream>
#include <ctime>#define Debug 0
#define Notice 1
#define Warning 2
#define Error 3const std::string msg[] =
{"Debug","Notice","Warning","Error"
};std::ostream &Log(std::string message, int level)
{std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;return std::cout;
}#endif// Comm.h
#pragma once#include <iostream>
#include <cstdio>
#include <cassert>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"using namespace std; // 将std直接展开简答,但不推荐#define PATH_NAME "/home/Joy"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE:4096KB)的整数倍// 将十进制转为十六进制
string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof buffer, "0x%x", k);return buffer;
}// shmServer.cc
#include "Comm.hpp"int main()
{// 1. 创建公共的key值key_t k = ftok(PATH_NAME, PROJ_ID);assert(k != -1);Log("create key done", Debug) << "server key: " << TransToHex(k) << endl;// 2. 创建共享内存(建议通信的发起者创建一个全新的共享内存)// 创建共享内存是也要指定权限int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid == -1){Log("create shm fail", Debug) << endl;exit(1);}Log("create shm done", Debug) << "shmid: " << shmid << endl;// 3. 建立页表映射(将共享内存挂接到当前进程地址空间)char* shmaddr = (char*)shmat(shmid, nullptr, 0);if(shmaddr == (char*)-1){Log("attch shm fail", Debug) << "shmid: " << shmid << endl;}Log("attch shm done", Debug) << "shmid: " << shmid << endl;// 4. 进程通信// 可以将共享内存看成一个大的字符串// 注意:共享内存创建好全部都会被置成0for(;;){printf("%s\n", shmaddr);if(strcmp(shmaddr, "quit") == 0) break;sleep(1);}// 5. 将指定的共享内存从自己的进程空间中去关联int n = shmdt(shmaddr);assert(n != -1);(void)n;Log("detach shm done", Debug) << "shmid: " << shmid << endl; // 6. 删除共享内存,IPC_RMID即便还有进程挂接该共享内存,依旧删除该共享内存n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;Log("delete shm done", Debug) << "shmid: " << shmid << endl; return 0;
}// shmClient.cc
#include "Comm.hpp"int main()
{// 1. 客户端只需要获取服务端创建的共享内存即可key_t k = ftok(PATH_NAME, PROJ_ID);if(k == -1){Log("create key fail", Error) << "client key: " << TransToHex(k) << endl;exit(1);}Log("create key done", Debug) << "client key: " << TransToHex(k) << endl;// 2. 获取共享内存int shmid = shmget(k, SHM_SIZE, 0);if(shmid == -1){Log("create shm fail", Error) << "client key: " << TransToHex(k) << endl;exit(2);}Log("create shm done", Debug) << "client key: " << TransToHex(k) << endl;// 3. 挂接共享内存char* shmaddr = (char*)shmat(shmid, nullptr, 0);if(shmaddr == (char*)-1){Log("attach shm failed", Error) << " client key : " << TransToHex(k) << endl;exit(3);}Log("attach shm success", Debug) << " client key : " << TransToHex(k) << endl;// 4. 使用,客户端将共享内存看做一个char类型的bufferwhile(true){ssize_t s = read(0, shmaddr, SHM_SIZE - 1);if(s > 0){shmaddr[s - 1] = '\0'; // 清除'\n'if(strcmp(shmaddr, "quit") == 0) break;}}// 以下代码是自动向共享内存中写入数据// char a = 'a';// for(; a <= 'z'; a++)// {// // shmaddr[a-'a'] = a;// // 我们是每一次都向shmaddr[共享内存的起始地址]写入// // snprintf(shmaddr, SHM_SIZE - 1, "hello server, 我是其他进程,我的pid: %d, inc: %c\n", getpid(), a);// // sleep(5);// }// strcpy(shmaddr, "quit");// 5. 去关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm done", Debug) << "client key: " << TransToHex(k) << endl;// 客户端不需要删除共享内存!return 0;
}
现象:
- 就算客户端没有向共享内存中写入数据,服务端也会一直读取。
- 只要通信双方使用共享内存,一方直接向共享内存中写入数据,另一方就可以马上看到对方写入的数据。共享内存是所有进程间通信(IPC)中速度最快的!因为其不需要过多的拷贝(不需要将数据给操作系统)!!!
- 以共享内存的方式进行进程间通信缺乏访问控制,会带来并发控制!比如:写端还没将全部数据写入,读端就已经开始读取了,这将会带来巨大的问题!
给共享内存添加访问控制
// Comm.hpp
#pragma once#include <iostream>
#include <cstdio>
#include <cassert>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"using namespace std; // 将std直接展开简答,但不推荐#define PATH_NAME "/home/Joy"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE:4096KB)的整数倍
#define FIFO_NAME "./fifo"// 将十进制转为十六进制
string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof buffer, "0x%x", k);return buffer;
}class Init
{
public:Init(){umask(0);int n = mkfifo(FIFO_NAME, 0666);assert(n == 0);(void)n;Log("create fifo success", Notice) << endl;}~Init(){unlink(FIFO_NAME);Log("delete fifo success", Notice) << endl;}
};#define READ O_RDONLY
#define WRITE O_WRONLYint OpenFIFO(std::string pathname, int flags)
{int fd = open(pathname.c_str(), flags);assert(fd != -1);return fd;
}// 服务端等待客户端唤醒
void Wait(int fd)
{Log("等待中......", Notice) << endl;uint32_t temp = 0;ssize_t s = read(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;}// 客户端唤醒服务端
void Signal(int fd)
{uint32_t temp = 1;ssize_t s = write(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;Log("唤醒中......", Notice) << endl;
}void CloseFIFO(int fd)
{close(fd);
}// shmServer.cc
#include "Comm.hpp"// 对应的程序在加载的时候,会自动构建全局变量,就要调用该类的构造函数 -- 创建管道文件
// 程序退出的时候,全局变量会被析构,自动调用析构函数,会自动删除管道文件
Init init; // 管道文件只有在服务端创建即可int main()
{// 1. 创建公共的key值key_t k = ftok(PATH_NAME, PROJ_ID);assert(k != -1);Log("create key done", Debug) << "server key: " << TransToHex(k) << endl;// 2. 创建共享内存(建议通信的发起者创建一个全新的共享内存)// 创建共享内存是也要指定权限int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid == -1){Log("create shm fail", Debug) << endl;exit(1);}Log("create shm done", Debug) << "shmid: " << shmid << endl;// 3. 建立页表映射(将共享内存挂接到当前进程地址空间)char* shmaddr = (char*)shmat(shmid, nullptr, 0);if(shmaddr == (char*)-1){Log("attch shm fail", Debug) << "shmid: " << shmid << endl;}Log("attch shm done", Debug) << "shmid: " << shmid << endl;// 4. 进程通信// 可以将共享内存看成一个大的字符串// 注意:共享内存创建好全部都会被置成0// 服务端以读方式打开管道文件int fd = OpenFIFO(FIFO_NAME, READ);for(;;){// 服务端等待客户端唤醒Wait(fd);printf("%s\n", shmaddr);if(strcmp(shmaddr, "quit") == 0) break;//sleep(1);}// 5. 将指定的共享内存从自己的进程空间中去关联int n = shmdt(shmaddr);assert(n != -1);(void)n;Log("detach shm done", Debug) << "shmid: " << shmid << endl; // 6. 删除共享内存,IPC_RMID即便还有进程挂接该共享内存,依旧删除该共享内存n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;Log("delete shm done", Debug) << "shmid: " << shmid << endl;CloseFIFO(fd); return 0;
}// shmClient.cc
#include "Comm.hpp"int main()
{// 1. 客户端只需要获取服务端创建的共享内存即可key_t k = ftok(PATH_NAME, PROJ_ID);if(k == -1){Log("create key fail", Error) << "client key: " << TransToHex(k) << endl;exit(1);}Log("create key done", Debug) << "client key: " << TransToHex(k) << endl;// 2. 获取共享内存int shmid = shmget(k, SHM_SIZE, 0);if(shmid == -1){Log("create shm fail", Error) << "client key: " << TransToHex(k) << endl;exit(2);}Log("create shm done", Debug) << "client key: " << TransToHex(k) << endl;// 3. 挂接共享内存char* shmaddr = (char*)shmat(shmid, nullptr, 0);if(shmaddr == (char*)-1){Log("attach shm failed", Error) << " client key : " << TransToHex(k) << endl;exit(3);}Log("attach shm success", Debug) << " client key : " << TransToHex(k) << endl;// 客户端以写方式打开管道文件int fd = OpenFIFO(FIFO_NAME, WRITE);// 4. 使用,客户端将共享内存看做一个char类型的bufferwhile(true){ssize_t s = read(0, shmaddr, SHM_SIZE - 1);if(s > 0){shmaddr[s - 1] = '\0'; // 清除'\n'Signal(fd); // 客户端唤醒服务端if(strcmp(shmaddr, "quit") == 0) break;}}// 以下代码是自动向共享内存中写入数据// char a = 'a';// for(; a <= 'z'; a++)// {// // shmaddr[a-'a'] = a;// // 我们是每一次都向shmaddr[共享内存的起始地址]写入// // snprintf(shmaddr, SHM_SIZE - 1, "hello server, 我是其他进程,我的pid: %d, inc: %c\n", getpid(), a);// // sleep(5);// }// strcpy(shmaddr, "quit");// 5. 去关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm done", Debug) << "client key: " << TransToHex(k) << endl;// 客户端不需要删除共享内存!return 0;
}
因为管道具有访问控制,我们只要给共享内存加个管道就可以实现进程通信的访问控制了。该管道文件并不是用来通信的,而是用来访问控制的,管道文件内的数据是多少并不重要!
👉system V消息队列(了解)👈
- 消息队列(先进先出)提供了一个从一个进程向另外一个进程发送一块数据的方法。
- 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。
- IPC 资源必须删除,否则不会自动清除,除非重启,所以 system V IPC 资源的生命周期随内核。
- 常用系统调用:ftok,msgget(创建消息队列),msgctl(控制消息队列),msgsnd(向消息队列发送数据),msgrcv(从消息队列中读取数据)等。
注:共享内存只有在当前映射连接数为 0 时才会被删除释放。
👉system V信号量👈
信号量主要用于同步和互斥的,下面先来看看什么是同步和互斥。
进程互斥
- 我们之前学习的所有的通信方式,本质都是优先解决一个问题:让不同的进程看到同一个资源!
- 让不同的进程看到同一个资源,比如共享内存,也带了一些时序问题,造成数据不一致问题。
- 多个进程(执行流)看到的公共的一份资源,称为临界资源或互斥资源。
- 进程中访问临界资源的代码,称为临界区。
- 多个执行流互相运行时互相干扰,是因为我们不加保护地访问了同样的资源(临界资源)。在非临界区,多个执行流不会互相干扰。
- 为了更好地进行临界区的保护,可以让多执行流在任何时候都只有一个进程进入临界区,这种特征称为互斥。
- 原子性是指事务的不可分割性,一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行,没有任何其他的中间状态。
通过看电影买票的例子来理解信号量
信号量是对临界资源的预定机制!!!
👉总结👈
本篇博客主要讲解了什么是共享内存、共享内存的原理、用共享内存实现客户端和服务端的通信、什么是消息队列、消息量以及进程互斥等等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️
相关文章:

【Linux】system V共享内存 | 消息队列 | 信号量
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉system V共…...

FSC的宣传许可 答疑
【FSC的宣传许可 答疑】问:已经采购了认证产品但没有贴FSC标签,是否可以申请宣传许可?答:不可以。要宣传您采用了FSC认证产品的前提条件之一是产品必须是认证且贴有标签的。如果产品没有贴标,则不可申请宣传许可。您的…...

Leetcode力扣秋招刷题路-0100
从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结 100. 相同的树 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是…...

协作对象死锁及其解决方案
协作对象死锁及其解决方案 1.前言 在遇到转账等的需要保证线程安全的情况时,我们通常会使用加锁的方式来保证线程安全,但如果无法合理的使用锁,很可能导致死锁。或者有时我们使用线程池来进行资源的使用,如调用数据库࿰…...

良许也成为砖家啦~
大家好,我是良许。 没错,良许成为砖家啦,绝不是口嗨,有图有真相! 有人会说,咦,这明明是严宇啊,跟你良许有啥关系? 额。。老读者应该知道良许的来历—— 鄙人真名严宇&a…...

Java中的编程细节
前言: 学习过程中有不少时候遇到一些看似简单,做起来事倍功半的问题。我也想自己是个聪明人,学东西一听就懂,一学就会,马上就能灵活应用。但这种事不能强求,要么自己要看个十遍二十遍最后理清逻辑…...

Yolov8从pytorch到caffe (一) 环境搭建
Yolov8从pytorch到caffe (一) 环境搭建 1. 创建虚拟环境2. 安装pytorch与v8相关库3. 测试安装是否成功4. 测试推理图像在windows上配置YOLOv8的环境,训练自己的数据集并转换到caffemodel1. 创建虚拟环境 利用conda创建虚拟环境 conda create -n yolo python=3.8 -y 并进入ac…...

2023年CDGA考试-第16章-数据管理组织与角色期望(含答案)
2023年CDGA考试-第16章-数据管理组织与角色期望(含答案) 单选题 1.在定义任何新组织或尝试改进现有组织之前了解当前组织的哪些方面非常重要? A.企业文化、运营模式和人员 B.业务战略、技术战略、数据战略 C.工具、方法和流程 D.事业环境因素、组织过程资产,行动路线图 …...

Stream——集合数据按照某一字段排序
文章目录前言假设业务场景排序前的准备正序排序1、数据集合的判空 Optional.isPresent()2、使用sort排序3、将排序后的数据流转换为list你以为这样就完了?倒序排序前言 之前,针对Stream链式编程中的几个方法做了大致的说明。详情可以参考: J…...

ubuntu:20.04编译arrow
1)拉取代码 git clone https://github.com/apache/arrow.git 2)切换分支 git checkout apache-arrow-11.0.0 3)拉入测试数据并设置环境变量 pushd arrow git submodule update --init export PARQUET_TEST_DATA"${PWD}/cpp/submodules/parquet-testing/da…...

2023如果纯做业务测试的话,在测试行业有出路吗?
直接抛出我的结论:手工做业务类测试,没有前途。 个人建议赶紧从业务测试跳出来,立即学习代码,走自动化测试方向。目前趋势,业务测试需要用自动化做。 为了让大家能够信服我的观点,本文将从以下方面进行阐…...

golang grpc ssl
无CA场景 在不考虑CA的场景下呢,client有client.key和client.crt,server有server.key和server.crt,生成方式可以如下: $ openssl genrsa -out server.key 2048 $ openssl req -new -x509 -days 3650 \-subj "/CGB/LChina/Og…...

华为服务器驱动下载及安装
1.服务器技术支持网站 https://support.xfusion.com/support/#/zh/home 2.选择软件下载 3.选择服务器型号 4.选择驱动 5.根据需求选择驱动 例如红帽7.4系统 6.安装驱动 自动安装驱动步骤: 1)使用BMC虚拟光驱挂载onboard_driver_xxx.iso: 2)mount /dev/sr0 /mnt …...

【Shell】常用命令合集
常用命令: 文件和目录: cd /home 进入 ‘/home’ 目录 cd … 返回上一级目录 cd …/… 返回上两级目录 cd - 返回上次所在目录 cp file1 file2 将file1复制为file2 cp -a dir1 dir2 复制一个目录 cp -a /tmp/dir1 . 复制一个目录到当前工作目录(.代表当前目录…...

15- 答题卡识别及分数判定项目 (OpenCV系列) (项目十五)
项目要点 图片读取 : img cv2.imread(./images/test_01.png)灰度图: gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)高斯模糊: blurred cv2.GaussianBlur(gray, (5, 5), 0) # 去噪点边缘检测: edged cv2.Canny(blurred, 75, 200)检测轮廓: cnts cv2.findContours(e…...

LeetCode 热题 C++ 146. LRU 缓存
力扣146 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否…...

Java线程池使用与原理解析(线程池优点、使用方法、参数含义及线程池运转机制)
为什么要使用线程池? JDK1.5后JUC包添加了线程池相关接口,在Java诞生之初并没有线程池这个概念。刚开始Java程序都是自行创建线程去处理任务。随着应用使用的线程越来越多,JDK开发者们发现有必要使用一个统一的类来管理这些线程,…...

mybatis入门配置
mybatis mybatis是一款持久层框架,用于简化JDBC开发 持久层:负责将数据保存到数据库的那一层代码JavaEE的三层架构:表现层、业务层、持久层、,就相当与mvc设计模式过程中的Controller、service、dao 1.创建一个maven模块&#…...

黑客入门(超级详细版)
据我了解,“黑客”大体上应该分为“正”、“邪”两类,正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善,而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情,因为邪派黑客所…...

Java多线程(三)---synchronized、Lock和volatile
Java内存模型(非JVM)Java内存模型(Java Memory Model简称JMM),是一种共享内存模型,是多线程的东西,并不是JVM(Java Virtual Machine(Java虚拟机)的缩写),这是俩玩意儿!&a…...

JVM-Java内存区域
运行时数据区:1、程序计数器:当前线程所执行的字节码指令的行号指示器。在Java虚拟机的概念模型里,字节码解释器的工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环…...

毕业季,毕业论文查重,paper系列五个免费查重网站推荐
推荐五个常用的免费查重网站 注意: (1)这些网站基本上都可以通过关注公众号或者转发等来获取免费查重机会,但有些也会有字数限制。每个网站的数据库可能不同,所以建议大家多换几个平台查一查,反正是免费的…...

破解票房之谜:为何高票房电影绕不过“猫眼们”?
如此火爆的春节档很多,如此毁誉参半的春节档鲜有。2023开年,集齐张艺谋、沈腾的《满江红》,以及有票房前作打底的《流浪地球2》接连两部春节档电影票房进入前十,为有些颓靡的中国电影市场注入了一针“强心剂”。与票房同样热闹起来…...

订单服务-----遇到的问题及解决方案
订单服务的问题及解决方案问题1:Feign远程调用时丢失请求头编辑出现这个Feign远程调用时丢失请求头的问题是因为Feign在远程调用的时候会创建一个新的请求,但是这个新的请求里啥都没有,没有cookie值,而这个cookie值里有成功登录后…...

项目经理如何度量项目?及项目度量指标实例【静说】
度量项目是项目经理的一个重要职责,通过度量项目,项目经理可以了解项目的进展情况,及时发现问题并采取相应的措施,以确保项目能够按时、按质、按预算完成。 分享给大家一些常见的项目度量指标: 1. 项目进度ÿ…...

我们应该如何优雅的处理 React 中受控与非受控
引言 大家好,我是19组清风。有段时间没有和大家见面了,最近因为有一些比较重要的事情(陪女朋友和换了新公司)在忙碌所以销声匿迹了一小段时间, 后续会陆陆续续补充之前构建 & 编译系列中缺失的部分,提…...

力扣热题100Day06:20. 有效的括号,21. 合并两个有序链表,22. 括号生成
20. 有效的括号 题目链接:20. 有效的括号 - 力扣(Leetcode) 思路:使用栈 (1)遇到左括号就将其对应的右括号压入到栈中 (2)如果遇到右括号 a. 如果弹出的元素与当前不等ÿ…...

【Yolov5】保姆级别源码讲解之-推理部分detect.py文件
推理部分之detect.py文件讲解1.下载Yolov5的源码2. 主函数讲解3.文件标头的注释4. main函数的5. run函数5.1 第一块参数部分5.2第二块,传入数据预处理5.3 第三块创建文件夹5.4 第四块 加载模型的权重5.5 第五块 Dataloader 加载模块5.6 第六块 推理部分 Run inferen…...

无重叠区间-力扣435-java贪心策略
一、题目描述给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。示例 1:输入: intervals [[1,2],[2,3],[3,4],[1,3]]输出: 1解释: 移除 [1,3] 后,剩下的区间没有重叠。…...

Python使用VTK对容积超声图像进行体绘制(三维重建)
目录VTK简介什么是体绘制?体绘制效果图流程CodeQ&AReferenceVTK简介 VTK(Visualization Toolkit)是一个用于3D计算机图形学、图像处理和可视化的开源软件包。它包括一组C类和工具,可以让用户创建和处理复杂的3D图形和数据可视…...