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

Linux : System V 共享内存

目录

一 前言

二 共享内存概念

 三 共享内存创建 

四 查看共享内存 

五 共享内存的删除

六 共享内存的关联 

七 共享内存去关联 

八 共享内存的使用(通信)

 九 共享内存的特点


一 前言

共享内存区是最快的IPC形式(进程间通信:IPC,InterProcess Communication) 一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用write()和read()来传递彼此的数据。


二 共享内存概念

 在上一篇进程间的管道通信中我们提到过,在进程间进行通信的时候,由于程序地址空间的存在,进程间的独立性使得他们之间的通信很麻烦,如果想要通信则需要两个进程看到同一份资源,上篇通过系统调用创建管道文件,使得进程之间看到共享资源(内存级文件),而本节进程间通信时进程之间看到的同一份资源是  共享内存。

🚀什么是共享内存呢? 

实际上,我们在学习程序地址空间的时候,如上图所示,我们已经看到了有一个区域的名字是共享区,在之前我们学习动静态库的时候,就说过动态库是在进程运行的时候加载到程序地址空间中的共享区的。当程序需要的时候,就会来到这部分读取数据。这一块内存就可以看作是一块只读共享区,共享内存进程通信实际上就是这个原理。

             共享内存进程通信就是在物理内存中开辟一块可以让所有进程都看到的内存空间,然后多个进程只需要向这块空间中读取或者写入数据,这样就达到了多个进程间一起通信的目的

也就是说,共享内存进程间的通信就是在物理内存中开辟一块空间当作共享内存,然后通信的进程们通过各自的页表将这块物理内存(共享内存)映射到各自的程序地址空间中 


 三 共享内存创建 

shmget()    (share memory  get)

这个接口的参数一共有三个 

  1. key_t key :  这是一个键值,key_t是一个整型,此参数其实是传入的是一个整数。通常这个键是通过  ftok() 函数从一个文件路径和一个项目ID生成的. 这个key值其实就是共享内存段在操作系统层面的唯一标识符。共享内存是Linux系统的一种进程通信的手段, 而操作系统中共享内存段一定是有许多的, 为了管理这些共享内存段, 操作系统一定会描述共享内存段的各种属性。类似其他管理方式,操作系统也会为共享内存维护一个结构体,在这个结构体内会维护一个key值,表示此共享内存在系统层面的唯一标识符,其一般由用户传入,为了区别每一块的共享内存,key的获取也是有一定的方法。

    ftok()函数的作用是将 一个文件 和 项目id 转换为一个System V IPC key值。用户就是使用这个函数来生成key值。

    他有两个参数,第一个参数显而易见是文件的路径,第二个参数则是随意的8bite位的数值。ftok()函数执行成功则会返回一个key值,这个key值是该函数通过传入文件的inode值和传入的proi_id值通过一定的算法计算出来的。由于每一个文件的inode值是唯一的,所以我们不用担心key值得重复。

  2. size_t size:  该参数传入的是想要开辟的共享内存的大小,单位是 byte字节。值得注意的是系统是按照4KB大小为单位开辟空间的,因为我们在磁盘一篇中学到系统I/O的单位大小就是4KB,也就是说无论这个参数传的是1、1024还是4096时,系统都会开辟4KB,但是虽然系统是按照4KB为单位开辟的空间,但是实际上用户能使用的空间的大小还是传入的size字节大小。

  3. int shmflg: 这里传入的是一组标识位,可以控制shemget的行为,它包括权限标志(类似0666)和命令标志,就像我们使用文件接口open时的O_WRONLY、O_RDONLY一样。共享内存接口标识符的两个最重要的宏是:IPC_CREAT、IPC_EXCL

    IPC_CREAT:传入该宏,表示创建一个新的共享内存段,若共享内存段已经存在,则获取此内存段;若不存在就创建一个新的内存段。

    IPC_EXCL:该宏需要和IPC_CREAT一起使用。表示如果创建的内存段不存在,则正常创建,若存在则返回错误。使用该宏保证的是此次使用shmget()接口创建成功时,创建出来的共享内存是全新的。

  4. shmget()函数的返回值,如果创建共享内存成功或者找到共享内存则返回共享内存的id,该id的作用是可以让通信的进程找到同一份块的资源。此id 是给上层用户使用,是为了标识共享内存。而key也是为了标识共享内存,但是是从系统层面来说。

🚍:接下来我们来学习和认识共享内存的创建

///comm.hpp/
#ifndef _COMM_HPP_
#define COMM_HPP_#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>#define PATHNAME "."
#define PROJ_ID 0x66           //目标标识符 int proj_id 就是一个整型
#define MAX_SIZE 4096
key_t getKey()
{key_t k = ftok(PATHNAME,PROJ_ID);//可以获取同一个keyif(k < 0){//cin ,cout,cerr -------->stdin stdout stderr--->0 1 2std::cerr<<errno<<":"<<strerror(errno)<<std::endl;//strerror(errno) 打印错误码对应的错误信息exit(1);}return k;
}
/shm_client.cpp///
#include "comm.hpp"
int main()
{key_t k=getKey();printf("key: 0x%x\n",k); return 0;
}
///shm_server.cpp
#include "comm.hpp"int main()
{key_t k=getKey();printf("key: 0x%x\n",k);return 0;
}

 运行结果:

 🚋:key的值是什么并不重要,重要的是能进行唯一性标识。

有了key之后,我们就可以用唯一的key进行共享内存的创建

//comm.hpp
//将一些函数进行封装到comm.hpp,然后client和server进行调用
int getShmHelper(key_t k,int flags)
{int shmid=shmget(k,MAX_SIZE,flags);//创建共享内存函数shmgetif(shmid < 0){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;exit(2);}return shmid;
}//获取共享内存
int getShm(key_t k)
{return getShmHelper(k,IPC_CREAT); //如果存在就获取,所以在客户端client,我们可以通过这个函数,来获取共享内存
}
////创建共享内存
int createShm(key_t k)//创建共享内存的工作,有服务端server来做
{return getShmHelper(k,IPC_CREAT | IPC_EXCL | 0600);//如果存在就创建失败,保证了我们创建的一定是新的共享内存,0600 代表创建的共享内存可读可写
}
//server.cpp
#include "comm.hpp"int main()
{key_t k=getKey();printf("key: 0x%x\n",k);int shmid=createShm(k);//服务端进行创建共享内存printf("shmid: %d\n",shmid);return 0;
}
///client.cpp
#include "comm.hpp"
int main()
{key_t k=getKey();printf("key: 0x%x\n",k);int shmid=getShm(k);//客户端进行获取共享内存printf("shmid: %d\n",shmid);return 0;
}

 运行结果:

 🍉这里的 key shmid 有什么区别呢?

key:是系统层面的,系统通过key来创建共享内存。

shmid:是上层用户层面,用户通过shmid来找到共享内存。


四 查看共享内存 

可是当我们再次运行服务端的时候,会发现出现如下问题:文件已存在

 这是什么原因呢?事实上,共享内存并不会随着进程的退出而退出,在创建共享内存的进程退出之后,共享内存是依旧存在于操作系统中的。而我们的服务端用key创建共享内存的时候,必须要求创建一个新的,如果当前的key对应的共享内存已经存在,则报错。

我们可以通过命令查看共享内存资源: ipcs -m  

这表明共享内存的生命周期是随着OS的,并不会因为进程的退出,而把共享内存删除。


五 共享内存的删除

我们可以使用 ipcrm -m (InterProcess Communication Remove Memory) 命令来删除。

那我们是通过 key 删除共享内存还是 shmid呢? 前面我们也说了key是内核层面,操作系统使用key,而删除共享内存,是指令操作,属于用户层面,所以我们通过shmid删除共享内存。

 我们还可以通过调用系统函数  shmctl 来对共享内存进行删除

我们在comm.hpp中对 shmctl进行封装成删除共享内存的函数。

/comm.hpp
void delShm(int shmid)
{if(shmctl(shmid,IPC_RMID,nullptr)==-1)//返回-1代表调用失败{std::cerr<<"shmctl"<<errno<<":"<<strerror(errno)<<std::endl;}
}
/sever.cpp
#include "comm.hpp"int main()
{key_t k=getKey();printf("key: 0x%x\n",k);int shmid=createShm(k);//服务端进行创建共享内存printf("shmid: %d\n",shmid);sleep(5);delShm(shmid);//调用删除共享内存函数}

 再次测试:


六 共享内存的关联 

🌏:前面我们讲述了服务端对共享内存的创建以及删除,但是要想使得两个进程进行通信,我们还需要进行共享内存对两个进程关联起来。

 系统调用函数 shmat (attach)

 我们在comm.hpp中对 shmat进行封装成关联共享内存的函数。

/comm.hpp//
//关联共享内存
void* attachShm(int shmid)
{void* mem =shmat(shmid,nullptr,0);if((long long)mem==-1){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;exit(3);}return mem;
}
///server.cpp
#include "comm.hpp"int main()
{key_t k=getKey();printf("key: 0x%x\n",k);int shmid=createShm(k);//服务端进行创建共享内存printf("shmid: %d\n",shmid);sleep(5);//关联共享内存char* start=(char*)attachShm(shmid);//返回值是共享内存地址printf("attach success,address start:%p\n",start);//删除sleep(5);delShm(shmid);return 0;
}

测试结果


七 共享内存去关联 

既然共享内存可以关联,自然也可以去关联,去关联并不是删除共享内存,而是去除进程与共享内存的联系。

系统调用函数 shmdt()    (detach)

我们在comm.hpp中对 shmdt进行封装成去关联共享内存的函数。

//comm.cpp////去关联共享内存
void detachShm(void* start)
{if(shmdt(start)==-1){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;}
}

八 共享内存的使用(通信)

🌿,在前面我们做了以下工作

共享内存的创建------------->关联共享内存---------->(这里我们将进行共享内存的通信)---------------->关联共享内存------------------------------------>删除共享内存 

//client.cpp
// 4.使用即通信const char* message="hello server, 我是另外一个进程正在和你通信";pid_t id=getpid();int count =0;while(true){sleep(1);//向共享内存输入消息snprintf(start,MAX_SIZE,"%s[pid:%d][消息编号:%d]",message,id,count++);//pid count message}
/server.cpp///
//4.使用while(true){printf("client say: %s\n",start);//打印由客户端发来的消息,直接打印共享内存地址即可sleep(1);}

测试结果:

 

 完整测试如下

/comm.hpp
#ifndef _COMM_HPP_
#define COMM_HPP_#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>#define PATHNAME "."
#define PROJ_ID 0x66           //目标标识符 int proj_id 就是一个整型
#define MAX_SIZE 4096
key_t getKey()
{key_t k = ftok(PATHNAME,PROJ_ID);//可以获取同一个keyif(k < 0){//cin ,cout,cerr -------->stdin stdout stderr--->0 1 2std::cerr<<errno<<":"<<strerror(errno)<<std::endl;//strerror(errno) 打印错误码对应的错误信息exit(1);}return k;
}int getShmHelper(key_t k,int flags)
{int shmid=shmget(k,MAX_SIZE,flags);//创建共享内存函数shmgetif(shmid < 0){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;exit(2);}return shmid;
}//获取共享内存
int getShm(key_t k)
{return getShmHelper(k,IPC_CREAT); //如果存在就获取,所以在客户端client,我们可以通过这个函数,来获取共享内存
}
////创建共享内存
int createShm(key_t k)//创建共享内存的工作,有服务端server来做
{return getShmHelper(k,IPC_CREAT | IPC_EXCL | 0666);//如果存在就创建失败,保证了我们创建的一定是新的共享内存
}//关联共享内存
void* attachShm(int shmid)
{void* mem =shmat(shmid,nullptr,0);if((long long)mem==-1){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;exit(3);}return mem;
}//去关联共享内存
void detachShm(void* start)
{if(shmdt(start)==-1){std::cerr<<errno<<":"<<strerror(errno)<<std::endl;}
}
//删除共享内存
void delShm(int shmid)
{if(shmctl(shmid,IPC_RMID,nullptr)==-1)//返回-1代表调用失败{std::cerr<<"shmctl"<<errno<<":"<<strerror(errno)<<std::endl;}
}#endif
client.cpp///
#include "comm.hpp"
int main()
{//1.获取keykey_t k=getKey();printf("key: 0x%x\n",k);//2.获取共享内存int shmid=getShm(k);//客户端进行获取共享内存printf("shmid: %d\n",shmid);sleep(5);//3.进行关联char* start=(char*)attachShm(shmid);printf("attach success,address start:%p\n",start);sleep(5);// 4.使用即通信const char* message="hello server, 我是另外一个进程正在和你通信";pid_t id=getpid();int count =0;while(true){sleep(1);//向共享内存输入消息snprintf(start,MAX_SIZE,"%s[pid:%d][消息编号:%d]",message,id,count++);//pid count message}// sleep(5);//5.去关联detachShm(start);return 0;
}
/server.cpp
#include "comm.hpp"int main()
{//1.创建keykey_t k=getKey();printf("key: 0x%x\n",k);//2.创建共享内存int shmid=createShm(k);//服务端进行创建共享内存printf("shmid: %d\n",shmid);sleep(5);//3. 关联共享内存char* start=(char*)attachShm(shmid);//返回值是共享内存地址printf("attach success,address start:%p\n",start);//4.使用while(true){printf("client say: %s\n",start);//打印由客户端发来的消息,直接打印共享内存地址即可sleep(1);}// // 5.去关联detachShm(start);sleep(5);//删除sleep(10);delShm(shmid);return 0;
}

 九 共享内存的特点

共享内存的优点:所以进程间通信,速度是最快的,能大大减少拷贝次数。

同样的代码,考虑到键盘输入和显示器输出 ,如果用管道来实现,会对数据进行几次拷贝?

共享内存的缺点:不给我们进行同步和互斥的操作,没有对数据做任何保护。

即客户端不进行写,服务端也一直进行读取,服务端不进行读取,客户端依然进行写入。 

相关文章:

Linux : System V 共享内存

目录 一 前言 二 共享内存概念 三 共享内存创建 四 查看共享内存 五 共享内存的删除 六 共享内存的关联 七 共享内存去关联 八 共享内存的使用&#xff08;通信&#xff09; 九 共享内存的特点 一 前言 共享内存区是最快的IPC形式&#xff08;进程间通信&#xff1…...

端到端语音识别案例

《DeepSeek大模型高性能核心技术与多模态融合开发&#xff08;人工智能技术丛书&#xff09;》(王晓华)【摘要 书评 试读】- 京东图书 语音识别这一技术正如其名&#xff0c;是通过精密地解析说话人的语音来识别并准确转写出其所说的内容。它不仅仅是一个简单的转录过程&#…...

【软件系统架构】微服务架构

一、引言 随着互联网技术的快速发展&#xff0c;传统的单体应用架构在面对复杂业务需求时逐渐暴露出诸多问题&#xff0c;如开发效率低、部署困难、扩展性差等。为了解决这些问题&#xff0c;微服务架构应运而生。本文将详细介绍微服务架构的定义、发展历史、特点、细分类型、优…...

【Kafka】消费者幂等性保障全解析

文章目录 消费者幂等性的重要性​基于消息唯一标识的幂等处理​消息去重表​缓存去重​ 基于事务的幂等处理​消费者事务与幂等性​ 幂等性保障的挑战与应对​性能开销​数据一致性​ 总结​ 在 Kafka 生态系统中&#xff0c;我们往往着重关注生产者端的幂等性&#xff0c;确保…...

Linux内核设计——(一)进程管理

目录 一、进程及线程简介 二、进程描述符 2.1 进程描述符简介 2.2 分配进程描述符 2.3 进程标识值 2.4 进程状态 2.5 进程上下文 三、进程创建 3.1 写时拷贝 3.2 fork()和vfork() 四、线程 4.1 Linux线程实现 4.2 内核线程 五、进程终结 5.1 删除进程描述符 5.…...

Ubuntu 22.04 LTS 下载英伟达驱动

在 Ubuntu 22.04 LTS 上安装 NVIDIA 驱动可以通过以下几种方法完成。以下是详细的步骤&#xff1a; 方法 1&#xff1a;使用 apt 包管理器安装&#xff08;推荐&#xff09; 这是最简单的方法&#xff0c;适合大多数用户。 更新系统包列表 sudo apt update检查可用的 NVIDIA 驱…...

22 安装第三方包

一、什么是第三方包 在 Python 的世界里&#xff0c;包就像是一个个功能强大的工具箱&#xff0c;它将多个 Python 模块收纳其中&#xff0c;而每个模块又蕴含着丰富多样的具体功能。可以说&#xff0c;一个包就是一系列同类功能的集合体&#xff0c;它们就像紧密协作的团队&a…...

深度学习deeplearn1

import torch # 导入 PyTorch 库&#xff0c;PyTorch 是一个用于深度学习和张量计算的强大库x torch.arange(12) # 创建一个包含从 0 到 11 的整数的一维张量 x # torch.arange 函数用于生成一个指定范围的整数序列print(x) # 打印张量 x 的内容print(x.shape) # 打印张量 x 的…...

oracle 常用函数的应用

在使用开发中会经常遇到数据类型转换、显示系统时间等情况&#xff0c;需要使用函数来实现。通过函数来实现业务需求会非常的省事便捷&#xff0c;函数可以用在适当的dml语句和查询语句中。 Oracle 数据库中主要使用两种类型的函数&#xff1a; (1)单行函数&#xff1a;对每一个…...

指纹浏览器技术解析:如何实现多账号安全运营与隐私保护

浏览器指纹的挑战与需求 在数字化运营场景中&#xff0c;浏览器指纹技术被广泛用于追踪用户行为。通过采集设备硬件参数&#xff08;如屏幕分辨率、操作系统&#xff09;、软件配置&#xff08;如字体、插件&#xff09;及网络特征&#xff08;如IP地址、时区&#xff09;&…...

“上云入端” 浪潮云剑指组织智能化落地“最后一公里”

进入2025年&#xff0c;行业智能体正在成为数实融合的核心路径。2025年初DeepSeek开源大模型的横空出世&#xff0c;通过算法优化与架构创新&#xff0c;显著降低算力需求与部署成本&#xff0c;推动大模型向端侧和边缘侧延伸。其开源策略打破技术垄断&#xff0c;结合边缘计算…...

CentOS 7 如何挂载ntfs的移动硬盘

CentOS 7 如何挂载ntfs的移动硬盘 前言一、查看硬盘并尝试挂载(提示无法挂载)二、yum安装epel-release提示yum被锁定三、强行终止yum的进程四、yum安装epel-release完成五、yum安装ntfs-3g六、此时可正常挂载NTFS硬盘 前言 CentOS 7默认情况下是不支持NTFS的文件系统&#xff…...

pytorch+maskRcnn框架训练自己的模型以及模型导出ONXX格式供C++部署推理

背景 maskrcnn用作实例分割时&#xff0c;可以较为精准的定位目标物体&#xff0c;相较于yolo只能定位物体的矩形框而言&#xff0c;优势更大。虽然yolo的计算速度更快。 直接开始从0到1使用maskrCNN训练自己的模型并并导出给C部署&#xff08;亲测可用&#xff09; 数据标注…...

①EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

型号 协议转换通信网关 EtherCAT 转 Modbus TCP MS-GW15 概述 MS-GW15 是 EtherCAT 和 Modbus TCP 协议转换网关&#xff0c;为用户提供一种 PLC 扩展的集成解决方案&#xff0c;可以轻松容易将 Modbus TCP 网络接入 EtherCAT 网络 中&#xff0c;方便扩展&#xff0c;不受限…...

Python扩展知识详解:lambda函数

目录 前言 1 基本知识点 语法 特点 代码示例 2 常见使用场景 1. 与高阶函数配合使用 2. 作为排序键来使用 3. 立即调用函数 4. 在字典中使用 3 高级用法&#xff08;进阶版&#xff09; 1. 多参数lambda 2. 设置默认参数 3. 嵌套lambda 注意事项 何时…...

信号量与基于环形队列的生产者消费者模型

目录 POSIX信号量 理解 使用 初始化 销毁 等待 发布信号量 基于环形队列的生产者消费者模型 POSIX信号量 理解 信号量可用于线程间的同步&#xff0c;它可以用于将一整块资源切成一个个的小部分以供并发访问。它实际上是一个计数器&#xff0c;但特别之处在于支持原子…...

《Oracle服务进程精准管控指南:23c/11g双版本内存优化实战》 ——附自动化脚本开发全攻略

正在学习或者是使用 Oracle 数据库的小伙伴&#xff0c;是不是对于那个一直启动且及其占用内存的后台进程感到烦躁呢&#xff1f;而且即使是手动去开关也显得即为麻烦&#xff0c;所以基于我之前所学习到的方法&#xff0c;我在此重新整理&#xff0c;让大家动动手指就能完成开…...

Java单列集合[Collection]

目录 1.Collection单列集合 1.1单列集合各集合特点 1.2、Collection集合 1.2.1、Collection方法 1.2.2、Collection遍历方式 1.2.2.1、迭代器遍历集合 1.2.2.2、增强for遍历集合 1.2.2.3、forEach遍历集合&#xff08;JDK8之后&#xff09; 1.2.2.4、遍历案例 1.3、Li…...

【C++重点】lambda表达式是什么

Lambda 表达式是 C11 引入的特性&#xff0c;它允许你定义匿名函数对象&#xff08;即没有名字的函数&#xff09;。Lambda 表达式可以在需要函数对象的地方直接定义函数&#xff0c;常用于 STL 算法和回调机制中。 lambda表达式基本语法 [捕获列表](参数列表) -> 返回类型…...

如何在ONLYOFFICE插件中添加自定义AI提供商:以通义千问和Kimi为例

随着 ONLYOFFICE AI 插件的发布&#xff0c;我们极大地提升了编辑器的默认功能。在ONLYOFFICE&#xff0c;我们致力于提供强大且灵活的解决方案&#xff0c;以满足您的特定需求。其中一项便是能够在 AI 插件中添加自定义提供商。在这篇文章中&#xff0c;我们将展示如何将通义千…...

Java基础-26-多态-认识多态

在Java编程中&#xff0c;多态&#xff08;Polymorphism&#xff09; 是面向对象编程的核心概念之一。通过多态&#xff0c;我们可以编写更加灵活、可扩展的代码。本文将详细介绍什么是多态、如何实现多态&#xff0c;并通过具体的例子来帮助你更好地理解这一重要概念。 一、什…...

Spark,配置hadoop集群1

配置运行任务的历史服务器 1.配置mapred-site.xml 在hadoop的安装目录下&#xff0c;打开mapred-site.xml&#xff0c;并在该文件里面增加如下两条配置。 eg我的是在hadoop199上 <!-- 历史服务器端地址 --> <property><name>mapreduce.jobhistory.address…...

【蓝桥杯算法练习】205. 反转字符串中的字符(含思路 + Python / C++ / Java代码)

【蓝桥杯算法练习】205. 反转字符串中的字符&#xff08;含思路 Python / C / Java代码&#xff09; &#x1f9e9; 题目描述 给定一个字符串 s&#xff0c;请你将字符串中的 英文字母字符反转&#xff0c;但其他 非字母字符保持在原位置&#xff0c;输出处理后的字符串。 …...

FPGA实现4K MIPI视频解码H265压缩网络推流输出,基于IMX317+VCU架构,支持4K60帧,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 MIPI 编解码方案我这里已有的视频图像编解码方案 3、详细设计方案设计框图FPGA开发板IMX317摄像头MIPI D-PHYMIPI CSI-2 RX Subsystem图像预处理Sensor …...

【Linux】网络概念

目录 网络模型 OSI七层模型 TCP/IP五层(或四层)模型 网络传输 网络传输基本流程 封装与分用 以太网通信&#xff08;局域网传输&#xff09; 跨网络传输 网络模型 OSI七层模型 TCP/IP五层(或四层)模型 网络层和传输层就是操作系统的一部分 网络传输 网络传输基本流程…...

【模拟CMOS集成电路设计】电荷泵(Charge bump)设计与仿真(示例:栅极开关CP+轨到轨输入运放+基于运放CP)

【模拟CMOS集成电路设计】电荷泵&#xff08;Charge bump&#xff09;设计与仿真 0前言1电荷泵1.1 PFD/CP/电容器级联1.2 PFD/CP/电容传递函数 2基本电荷泵(CP)结构2.1“漏极开关”结构2.2“源极开关”结构2.3“栅极开关”结构 3 CP的设计与仿真13.1 P/N电流源失配仿真3.2 电荷…...

minecraft.service 文件配置

minecraft.service 文件配置 # /etc/systemd/system/minecraft.service [Unit] DescriptionMinecraft Fabric Server Afternetwork.target Wantsnetwork-online.target[Service] Usermcfabricuser Groupmcfabricuser WorkingDirectory/minecraft/1.21.1-fabric-server ExecStar…...

Kafka消息丢失全解析!原因、预防与解决方案

作为一名高并发系统开发工程师&#xff0c;在使用消息中间件的过程中&#xff0c;无法避免遇到系统中消息丢失的问题&#xff0c;而Kafka作为主流的消息队列系统&#xff0c;消息丢失问题尤为常见。 在这篇文章中&#xff0c;将深入浅出地分析Kafka消息丢失的各种情况&#xf…...

VS Code 云服务器远程开发完整指南

VS Code Ubuntu 云服务器远程开发完整指南 远程开发是现代开发者的标配之一&#xff0c;特别是在使用云服务器&#xff08;如 Ubuntu&#xff09;进行部署、测试或大项目开发时&#xff0c;利用 VS Code 的 Remote-SSH 插件&#xff0c;可以像本地一样顺滑操作远程服务器。本…...

Linux孤儿进程和僵尸进程

目录 1、孤儿进程 2、僵尸进程 在 Linux 系统中&#xff0c;父子进程关系的生命周期不同&#xff0c;导致会产生两类特殊进程&#xff1a;孤儿进程和僵尸进程。这两类进程在系统资源管理中起着重要作用。 1、孤儿进程 孤儿进程指的是父进程先于子进程结束&#xff0c;导致子…...