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

Linux系统编程--进程间通信

目录

1. 介绍

1.1 进程间通信的目的

1.2 进程间通信的分类

2. 管道

2.1 什么是管道

2.2 匿名管道

2.2.1 接口

2.2.2 步骤--以父子进程通信为例

2.2.3 站在文件描述符角度-深度理解

2.2.4 管道代码

2.2.5 读写特征

2.2.6 管道特征

2.3 命名管道

2.3.1 接口

2.3.2 代码实现

 2.3.3 匿名管道和命名管道的区别

3. system V共享内存

3.1 共享内存的原理 

3.2 步骤

3.3 系统接口

3.4 代码

3.5 共享内存的优缺点

4.信号量

4.1 相关概念

4.2 信号量 -- 对资源的一种预定

4.3 系统接口


1. 介绍

1.1 进程间通信的目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件                        (如进程终止 时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望                      能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变
  • 有时候也需要多进程协同进行工作

如何理解进程间通信的本质问题呢?

  • OS需要直接/间接的给通信双方的进程提供"内存空间"
  • 要通信的不同进程必须看到同一份公共资源

1.2 进程间通信的分类

  • 管道
  • SystemV(本文只讨论共享内存) -- 让通信过程可以跨主机
  • POSIX -- 聚焦在本地通信

2. 管道

2.1 什么是管道

  • 管道是 Unix 中最古老的进程间通信的形式
  • 我们把从一个进程连接到另一个进程的一个数据流称为一个 管道  

管道又分匿名管道和命名管道两种。 

2.2 匿名管道

2.2.1 接口

#include <ustdio.h>

int pipe(int pipefd[2]); 
参数:piepfd[]为输出型参数,pipefd[0]为读文件描述符,pipefd[1]为写文件描述符,若为其他的文件描述符使用,一般这两个fd分别为3、4。

返回值:创建成功返回0,失败返回-1 

2.2.2 步骤--以父子进程通信为例

  • 父进程利用pipe接口创建管道,分别以读和写打开一个文件 
  • 父进程fork出子进程
  • 父进程关闭fd[1],子进程关闭fd[0]
  • 这样父进程就可以往管道文件中写数据,子进程从管道文件中读数据,实现了父子进程的通信

注:管道一般是单向的,其实管道也是一个文件("内核级文件")--不需要进行磁盘IO(当然也可以用磁盘文件来实现这个管道操作,但是要进行磁盘读取,太慢了)

 若是管道中没有数据了,但是读端还在读,OS会直接阻塞当前正在读取的进程。

2.2.3 站在文件描述符角度-深度理解

2.2.4 管道代码

        在这个代码部分,可以实验当读快写慢、读慢写快、只读关闭、只写关闭四种情况,这里只给出了只有读关闭的情况

  #include <iostream>                                                                                                                                                   #include <cstdio>    #include <unistd.h>    #include <cassert>    #include <sys/stat.h>    #include <sys/wait.h>    #include <fcntl.h>    #include <cstring>    using namespace std;    int main()    {    // 第一步:创建管道文件    int fds[2];    int n = pipe(fds);    assert(n == 0);    // 0 1 2应该是被占用的 _-> 3 4    cout << "fds[0]: " << fds[0] << endl;    cout << "fds[1]: " << fds[1] << endl;    // 第二步:fork    pid_t id = fork();    assert(id >= 0);    if(id == 0)    {    // 子进程的通信代码 子进程写入    close(fds[0]);    // 通信代码    // string msg = "hello, i am child!";    int cnt = 0;    const char* s = "我是子进程,我正在给你发消息!";    while(1)    {    cnt++;    char buffer[1024]; // 只有子进程能看到    snprintf(buffer, sizeof buffer, "child->parent say: %s[%d][%d]", s, cnt, getpid());    // 往文件中写入数据    write(fds[1], buffer, strlen(buffer));    // sleep(50); // 细节 每隔一秒写一次    // break;    }cout << "子进程关闭写端" << endl;close(fds[1]);exit(0);}                                                                                                                                                                 // 父进程的通信代码  父进程读取close(fds[1]);while(1){char buffer[1024];// cout << "AAAAAAAAAAAAAAA" <<endl;// 父进程在这里阻塞等待ssize_t s = read(fds[0], buffer, sizeof(buffer) - 1);//  cout << "BBBBBBBBBBBBBBB" <<endl;if(s > 0) {buffer[s] = 0;cout << " Get Message# " << buffer <<" | my pid: " << getpid() << endl;}else if(s == 0){cout << "read: " << s << endl;break;}// cout << "Get Message#" << buffer << " | my pid: " << getppid() << endl;// 细节:父进程可没有进行sleep//sleep(5);// close(fds[0]);break;}close(fds[0]);int status = 0;cout << "父进程关闭读端" << endl;n = waitpid(id, &status, 0);assert(n == id);cout << "pid->" << n << ":" << (status & 0x7F) << endl; // 信号为13:SIGPIPE 中止了写入进程return 0;}

       由上面代码结果可以看出,当读关闭时,OS会终止写端,给写进程发送信号,终止写端。写进程收到13号信号

2.2.5 读写特征

  • 读快,写慢 -- 读进程会阻塞,等到管道中有数据时继续读取,子进程没有写入的那段时间,                          若管道中没有数据时,父进程会在read处阻塞等待
  • 读慢,写快 -- 写进程正常写数据,管道写满时,会在write处阻塞,读进程就绪时,继续读取                         数据
  • 写关闭 -- 管道中的数据会被读取完毕后返回EOF,此时 read 函数会返回0,最后等待子进程关                  闭读端
  • 读关闭 -- OS会中止写端,给写端发送信号--13 SIGPIPE,终止写端

2.2.6 管道特征

  • 管道的生命周期随进程
  • 管道可以用来进行具有血缘关系的进程通信,常用于父子进程
  • 管道是面向字节流的
  • 单向通信 -- 半双工通信
  • 互斥与同步机制 -- 对共享资源进行保护额方案

2.3 命名管道

  • 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
  • 命名管道是一种特殊类型的文件
  • 在用命名管道实现两个进程通信时,任意一个进程调用mkfifo创建命名管道即可

2.3.1 接口

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char* pathname, mode_t mode);

参数:pathname:命名管道的路径名  mode:管道权限

返回值:成功返回0;失败返回-1,并设置errno来指示错误原因

int unlink(const char* pathname);  --在进程结束后,清理和删除命名管道。

参数:命名管道的路径名

返回值:成功返回0;失败返回-1,并设置errno来指示错误原因

 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

mkfifo filename  # filename为命名管道文件名

2.3.2 代码实现

用命名管道实现 server&client 通信
server.cc:
#include <iostream>
#include "comm.hpp"
using namespace std;int main()
{bool r = createFifo(NAMED_PIPE);assert(r);(void)r;cout << "server begin" << endl;int rfd  =open(NAMED_PIPE, O_RDONLY);  // 只读方式打开cout << "server end" << endl;                                                                        if(rfd < 0)                                                                                          {                                                                                                    cout << "文件打开失败!" << endl;                                                                exit(1);                                                                                         }                                                                                                    // read                                                                                              char buffer[1024];                                                                                   while(true)                                                                                          {                                                                                                    ssize_t s = read(rfd, buffer, sizeof buffer - 1);                                                if(s > 0)                                                                                        {                                                                                                buffer[s] = 0;                                                                               std::cout << "client->server:" << buffer << endl;                                            }                                                                                                else if(s == 0)    {                                                                                                cout << "client quit, me too!" << endl;                                                      break;                                                                                                                                                              }    else{    cout << "err string:" << strerror(errno) << endl;    break;    }    }close(rfd);// sleep(10);removeFifo(NAMED_PIPE);return 0;
}

client.cc

#include <iostream>    
#include "comm.hpp"    
using namespace std;    int main()    
{    // 与server打开同一个文件    cout << "client begin" << endl;    int wfd = open(NAMED_PIPE, O_WRONLY);    cout << "client end" << endl;    if(wfd < 0)    {    cout << "文件打开失败!" << endl;    exit(1);    }    // write    char buffer[1024];    while(true)    {    cout << "Please Say# ";                                                                                                                                         fgets(buffer, sizeof(buffer)-1, stdin);    if(strlen(buffer) > 0) buffer[strlen(buffer)-1] = 0;    ssize_t s = write(wfd, buffer, strlen(buffer));    assert(s == strlen(buffer));    (void)s;    }    close(wfd);    return 0;    
}   

comm.hpp 

#pragma once    #include <string>    
#include <iostream>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <cstring>    
#include <cassert>    
#include <cerrno>    
#include <unistd.h>    
#include <sys/wait.h>    
#include <fcntl.h>    #define NAMED_PIPE "/tmp/mypipe.106"    bool createFifo(const std::string& path)    
{    umask(0);    int n = mkfifo(path.c_str(), 0600);  // 只允许拥有者通信    if(n == 0) return true;    else{                                                                                                                                                               std::cout << "erro" << errno << "err string: " << strerror(errno) << std::endl;    return false;    }    
}    void removeFifo(const std::string & path)    
{    int n = unlink(path.c_str());    assert(n == 0); // debug有效,release里面就无效    (void)n;  // 不想有警告    
}   

可以看到client可以向server端发送数据,server收到并打印到屏幕中,实验结果如下图所示: 

下图为命名管道的信息: 

 

 2.3.3 匿名管道和命名管道的区别

  • 匿名管道由pipe函数创建并打开。
  • 命名管道由mkfifo函数创建,打开用open
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

3. system V共享内存

3.1 共享内存的原理 

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

原理:是不同的进程通过各自的PCB和页表访问同一快共享内存

3.2 步骤

  • 申请一块空间
  • 将创建好的内存映射(将进程和共享内存挂接)到不同的进程地址空间
  • 若未来不想通信:取消进程和内存的映射关系--去关联、释放共享内存 

3.3 系统接口

#include <sys/ipc.h>

#include <sys.shm.h>

int shmget(key_t key, size_t size, int shmflg);

参数:key: 进行唯一性标识 -- 将key使用shmget设置进入共享内存属性中,用来表示共享                                                    内存在内核中的唯一性

           size:申请空间大小--一般为4KB的整数倍

           shmflg:IPC_CREAT--如果指定的共享内存不存在,创建;如果存在,获取共享内存

                          IPC_EXCL--无法单独使用  使用:IPC_CREAT|IPC_EXCL:如果不存在,                            创建--创建的一定是一个新的共享内存;存在则出错返回,还可以通过其                                设置共享内存的权限
返回值:成功返回标识符shmid;失败,返回-1,与文件不同

key_t ftok(char* pathname, char proj_id); --
使用给定路径名命名的文件的标识(必须引用一个现有的,可访问的文件)和proj_id的最低有效8位(必须是非零的)来生成key_t类型的System V IPC密钥

返回值:成功返回key_t值,失败返回-1

解析:

        创建共享内存时,如何保证其在系统中是唯一的?-- 通过参数key确定的,只要保证另一个要通信的进程看到相同的key值,通过在各个共享内存的属性中查找相同的key,即可找到同一块共享内存--通过相同的pathname和proj_id在不同的进程中调用ftok获得相同的key。那么key在哪里呢? -- 在结构体struct stm中。

IPC资源的特征:共享内存的生命周期是随OS的,不是随进程的,若没有对共享内存进行手动的删除,那么该资源不会消失

查看IPC资源的命令:ipcs -m(共性内存)  /-q(消息队列)/-s(信号量)

删除IPC资源的执行:ipcrm -m shmid

操作共享内存

int shmctl(int shmid, int cmd, struct shmid_ds* buf);

参数:shmid:shmget的返回值--要控制哪一个共享内存

           cmd:IPC_RMID -- 删除共享内存段 谁创建谁删除

                      IPC_STAT -- 获取共享内存属性

                      IPC_SET -- 设置共享内存属性

           buf:

返回值:失败返回-1

关联进程

void* shmat(int shmid, const void* shmaddr, int shmflg);

参数:shmid:

           shmaddr:将共享内存映射到哪一个地址空间中,一般设为nullptr 核心自动选择                                      一个地址

           shmflg:一般设置为0,读写权限

返回值:共享内存空间的起始地址

去关联:并不是删除共享内存,而是去除PCB和共享内存的映射关系

int shmdt(const void* shmaddr);

参数:shmaddr-由shmat所返回的指针
返回值:失败返回-1

3.4 代码

// common.hpp
#ifndef _COMM_HPP_                                                                                                                                                      
#define _COMM_HPP_    #include <iostream>    
#include <sys/ipc.h>    
#include <sys/types.h>    
#include <sys/shm.h>    
#include <cerrno>    
#include <cstring>    
#include <cstdlib>    
#include <unistd.h>    #define PATHNAME "."    
#define PROJ_ID 0x66    
#define MAX_SIZE 4096    key_t getKey()    
{    key_t k = ftok(PATHNAME, PROJ_ID);  // 可以获取同样的key!    if(k < 0)    {    // cin cout cerr -> stdin stdout stderr -> 0,1,2    std::cerr << errno << ":" << strerror(errno) << std::endl;    exit(1);    }    return k;    
}    int getShmHelper(key_t k, int flags)    
{    int shmId = shmget(k, MAX_SIZE, flags);    if(shmId < 0)    {    std::cerr << errno << ":" << strerror(errno) << std::endl;    exit(2);    }    return shmId;    
}    
// 给之后的进程获取共享内存
int getShm(key_t k)
{return getShmHelper(k, IPC_CREAT/*可以设定为0*/); 
}// 给第一个进程使用 创建共享内存 
int creatShm(key_t k)
{return getShmHelper(k, IPC_EXCL | IPC_CREAT | 0600); // 0600为权限
}void *attachShm(int shmId)
{void *mem = shmat(shmId, nullptr, 0);  // 64位系统 指针占8字节if((long long)mem == -1L){std::cerr << "shmat " << 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){std::cerr << errno << ":" << strerror(errno) << std::endl;}
}#endif//shm_client.cc//
#include "common.hpp"                                                                                                                                                   
using namespace std;    int main()    
{    key_t k = getKey();    printf("0x%x\n", k);    int shmId = getShm(k);    printf("shmId:%d\n", shmId);    // 关联    char *start = (char*)attachShm(shmId);    printf("sttach success, address start: %p\n", start);    // 使用    const char* message = "hello server, 我是另一个进程,正在和你通信!";    pid_t id = getpid();    int cnt = 1;    // char buffer[1024];    while(true)    {    sleep(1);    // 直接将需要传递的信息写在共享内存字符串中 省去了很多拷贝的过程 提高了传输信息的效率    snprintf(start, MAX_SIZE, "%s[pid:%d][消息编号:%d]", message, id, cnt++);    // snprintf(buffer, sizeof(buffer), "%s[pid:%d][消息编号:%d]", message, id, cnt);    // memcpy(start, buffer, strlen(buffer)+1);    }    // 去关联    detachShm(start);    // done    return 0;    
} /shm_server.cc///
#include "common.hpp"                                                                                                                                                   
using namespace std;    int main()    
{    key_t k = getKey();    printf("0x%x\n", k);    // 申请共享内存    int shmId = creatShm(k);    printf("shmId:%d\n", shmId);    sleep(3);    // 关联    // 将共享内存看为一个字符串    char *start = (char*)attachShm(shmId);    printf("sttach success, address start: %p\n", start);    // 使用    while(true)    {    printf("client say: %s\n", start);    sleep(1);    }    // 去关联    detachShm(start);    sleep(5);    // 删除共享内存    delShm(shmId);    return 0;    
}    

上面的代码我们看到的现象是:

通过共享内存的方式实现了进程间通信

3.5 共享内存的优缺点

优点:

  • 共享内存是所有通信中最快的,大大减少数据的拷贝次数

缺点:

  • 不会给我们进行同步和互斥,没有对数据进行任何保护

问题--同样的代码,管道和共享内存方式实现各需要多少次拷贝 ?

4.信号量

4.1 相关概念

信号量 -- 本质是一个计数器,通常用来表示公共资源中,资源数量的多少问题

公共资源 -- 被多个进程同时访问的资源,访问没有保护的公共资源时,可能会导致数据不一致                         问题

为什么要让不同进程看到同一份资源? -- 实现进程间的协同工作,但是进程是具有独立性的,      为了让进程看到同一份资源,提出了进程间通信的方法,但是又带来了新的问题--数据不一致问题

临界资源:将被保护起来的公共资源称为临界资源,但是大部分的资源是独立的,只有少量的属于临                      界资源,资源就是内存、文件、网络等

临界区:进程访问临界资源的代码被称为临界区,与之对应的为非临界区

保护公共资源:互斥、同步

原子性:要么不做,要做就做完,只有两种状态

4.2 信号量 -- 对资源的一种预定

为什么要有信号量?

设sem=20; sem--;// P操作,访问公共资源;sem++;// V操作,释放公共资源  --PV操作

所有的进程在访问公共资源前都必须先申请sem信号量,前提是所有进程必须先看到同一个信号量,那么信号量本身就是公共资源--也要保证自己的安全--信号量++、--的操作是原子操作

如果一个信号量的初始值为1,二维信号量/互斥信号量

4.3 系统接口

头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

申请信号量

int semget(key_t key, int nsems, int semflg);

参数:   key:对申请的信号量进行唯一性标识

              nsems:申请几个信号量,与信号量的值无关

              semflg:与共享内存的flag相同含义

返回值:成功返回信号量标识符semid,失败返回-1

删除信号量

int semctl(int semid, int semnum, int cmd,...);

参数:semid:信号量id,semget返回的值

           semnum:信号量集的下标

           cmd:IPC_RMID、IPC_STAT、IPC_SET

返回值:失败返回-1 

操作信号量

int semop(int semid, struct sembuf* sops, unsigned nsops);

参数:semid:信号量id

           sops:

信号量的详细操作会在多线程部分讲解 

相关文章:

Linux系统编程--进程间通信

目录 1. 介绍 1.1 进程间通信的目的 1.2 进程间通信的分类 2. 管道 2.1 什么是管道 2.2 匿名管道 2.2.1 接口 2.2.2 步骤--以父子进程通信为例 2.2.3 站在文件描述符角度-深度理解 2.2.4 管道代码 2.2.5 读写特征 2.2.6 管道特征 2.3 命名管道 2.3.1 接口 2.3.2…...

docker-本地部署-后端

前置条件 后端文件 这边是一个简单项目的后端文件目录 docker服务 镜像文件打包 #命令行 docker build -t author/chatgpt-ai-app:1.0 -f ./Dockerfile .红框是docker所在文件夹 author&#xff1a;docker用户名chatgpt-ai-app&#xff1a;打包的镜像文件名字:1.0 &#…...

TLS + OpenSSL + Engine + PKCS#11 + softhsm2 安全通信

引擎库路径只有在 /lib 下才能被 "LOAD" 识别到&#xff0c;OpenSSL的ReadMe给的示例在/lib&#xff0c;大概是在构建OpenSSL时默认的configure指定了lib路径 // #define PKCS11_ENGINE_PATH "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so" #define …...

Unity实现简单的MVC架构

文章目录 前言MVC基本概念示例流程图效果预览后话 前言 在Unity中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;框架是一种架构模式&#xff0c;用于分离游戏的逻辑、数据和用户界面。MVC模式可以帮助开发者更好地管理代码结构&#xff0c;提高代码的可维护性…...

【简单讲解下OneFlow深度学习框架】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

FastGPT 调用Qwen 测试Hello world

Ubuntu 安装Qwen/FastGPT_fastgpt message: core.chat.chat api is error or u-CSDN博客 参考上面文档 安装FastGPT后 登录&#xff0c; 点击右上角的 新建 点击 这里&#xff0c;配置AI使用本地 ollama跑的qwen模型 问题&#xff1a;树上有3只鸟&#xff0c;开了一枪&#…...

Golang-GMP

GMP调度 golang-GMP语雀笔记整理 GMP调度设计目的&#xff0c;为何设计GMP?GMP的底层实现几个核心数据结构GMP调度流程 设计目的&#xff0c;为何设计GMP? 无论是多进程、多线程目的都是为了并发提高cpu的利用率&#xff0c;但多进程、多线程都存在局限性。比如多进程通过时…...

【PythonWeb开发】Flask自定义模板路径和静态资源路径

在大型的 Flask 项目中&#xff0c;确实可能会有多个子应用&#xff08;Blueprints&#xff09;&#xff0c;每个子应用可能都有自己的静态文件和模板。为了更好地管理和组织这些资源&#xff0c;可以使用static_folder 和template_folder 属性来统一管理。必须同时设置好主应用…...

Java对象创建过程

在日常开发中&#xff0c;我们常常需要创建对象&#xff0c;那么通过new关键字创建对象的执行中涉及到哪些流程呢&#xff1f;本文主要围绕这个问题来展开。 类的加载 创建对象时我们常常使用new关键字。如下 ObjectA o new ObjectA();对虚拟机来讲首先需要判断ObjectA类的…...

Does a vector database maintain pre-vector chunked data for RAG systems?

题意&#xff1a;一个向量数据库是否为RAG系统维护预向量化分块数据&#xff1f; 问题背景&#xff1a; I believe that when using an LLM with a Retrieval-Augmented Generation (RAG) approach, the results retrieved from a vector search must ultimately be presented…...

Rust-11-错误处理

Rust 将错误分为两大类&#xff1a;可恢复的&#xff08;recoverable&#xff09;和 不可恢复的&#xff08;unrecoverable&#xff09;错误。对于一个可恢复的错误&#xff0c;比如文件未找到的错误&#xff0c;我们很可能只想向用户报告问题并重试操作。不可恢复的错误总是 b…...

自动化测试:使用Postman进行接口测试与脚本编写

Postman 是一种流行的 API 测试工具&#xff0c;广泛应用于开发和测试过程中。它不仅可以用于手动测试&#xff0c;还支持自动化测试和脚本编写&#xff0c;以确保 API 的可靠性和性能。本文将详细介绍如何使用 Postman 进行接口测试与脚本编写&#xff0c;帮助你更高效地进行自…...

ONLYOFFICE 8.1 桌面编辑器测评:引领数字化办公新潮流

目录 前言 下载安装 新功能概述 1.PDF 编辑器的改进 2. 演示文稿中的幻灯片版式 3.语言支持的改进 4. 隐藏“连接到云”板块 5. 页面颜色设置和配色方案 界面设计&#xff1a;简洁大方&#xff0c;操作便捷 性能评测&#xff1a;稳定流畅&#xff0c;高效运行 办公环…...

基于大语言模型LangChain框架:知识库问答系统实践

ChatGPT 所取得的巨大成功&#xff0c;使得越来越多的开发者希望利用 OpenAI 提供的 API 或私有化模型开发基于大语言模型的应用程序。然而&#xff0c;即使大语言模型的调用相对简单&#xff0c;仍需要完成大量的定制开发工作&#xff0c;包括 API 集成、交互逻辑、数据存储等…...

解锁Transformer的鲁棒性:深入分析与实践指南

&#x1f6e1;️ 解锁Transformer的鲁棒性&#xff1a;深入分析与实践指南 Transformer模型自从由Vaswani等人在2017年提出以来&#xff0c;已经成为自然语言处理&#xff08;NLP&#xff09;领域的明星模型。然而&#xff0c;模型的鲁棒性——即模型在面对异常、恶意或不寻常…...

mybatis#号和$区别

在MyBatis中&#xff0c;#{}和${}都是用于实现动态SQL的占位符&#xff0c;但它们在使用场景和安全性上有明显的区别&#xff1a; 用途区别&#xff1a; #{}主要用于传递接口传输过来的具体数据&#xff0c;如参数值&#xff0c;它可以防止SQL注入&#xff0c;因为MyBatis会…...

AI绘画 Stable Diffusion【实战进阶】:图片的创成式填充,竖图秒变横屏壁纸!想怎么扩就怎么扩!

大家好&#xff0c;我是向阳。 所谓图片的创成式填充&#xff0c;就是基于原有图片进行扩展或延展&#xff0c;在保证图片合理性的同时实现与原图片的高度契合。是目前图像处理中常见应用之一。之前大部分都是通过PS工具来处理的。今天我们来看看在AI绘画工具 Stable Diffusio…...

Linux内核 -- 汇编结合ko案例之PMU获取cpu cycle技术

ARMv7汇编实现周期计数读取与清空 本文档详细描述了如何在ARMv7平台上使用汇编语言编写周期计数器读取与清空函数&#xff0c;如何在内核模块中导出这些函数供其他模块调用&#xff0c;以及如何使用Netlink接口供用户态程序进行调用。 1. 汇编函数实现 首先&#xff0c;编写…...

探索 Symfony 框架:工作原理、特点及技术选型

目录 1. 概述 2. Symfony 的工作原理 2.1 MVC 架构 2.2 前端控制器模式 2.3 路由机制 2.4 依赖注入容器 2.5 事件驱动架构 3. Symfony 的特点 3.1 高度可扩展性 3.2 强大的社区支持和生态系统 3.3 优秀的性能和可伸缩性 3.4 严格的代码规范和最佳实践 4. Symfony …...

从万里长城防御体系看软件安全体系建设@安全历史03

长城&#xff0c;是中华民族的一张重要名片&#xff0c;是中华民族坚韧不屈、自强不息的精神象征&#xff0c;被联合国教科文组织列入世界文化遗产名录。那么在古代&#xff0c;长城是如何以其复杂的防御体系&#xff0c;一次次抵御外族入侵&#xff0c;而这些防御体系又能给软…...

ISO 19110操作要求类中的/req/operation/formal-definition详细解释

/req/operation/formal-definition 要求: 每个要素操作实体必须具有一个形式定义&#xff08;formal definition&#xff09;&#xff0c;该定义应明确描述操作的行为和影响。 具体解释 定义 要素操作实体&#xff08;feature operation entity&#xff09;&#xff1a;这…...

豆包大语言模型API调用错误码一览表

本文介绍了您可能从 API 和官方 SDK 中看到的错误代码。 http code说明 400 原因&#xff1a;错误的请求&#xff0c;例如缺少必要参数&#xff0c;或者参数不符合规范等 解决方法&#xff1a;检查请求后重试 401 原因&#xff1a;认证错误&#xff0c;代表服务无法对请求进…...

AI辅助设计:如何通过机器学习革新创意工作流程

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法&#xff0c;大数据&#xff0c;深度学习 &#x1f492; 公众号…...

轻松解锁电脑强悍性能,4000MHz的玖合星舞 DDR4 内存很能打

轻松解锁电脑强悍性能&#xff0c;4000MHz的玖合星舞 DDR4 内存很能打 哈喽小伙伴们好&#xff0c;我是Stark-C~ 很多有经验的电脑玩家在自己DIY电脑选购内存条的时候&#xff0c;除了内存总容量&#xff0c;最看重的参数那就是频率了。内存频率和我们常说的CPU主频一样&…...

SpringBoot | 使用jwt令牌实现登录认证,使用Md5加密实现注册

对于登录认证中的令牌&#xff0c;其实就是一段字符串&#xff0c;那为什么要那么麻烦去用jwt令牌&#xff1f;其实对于登录这个业务&#xff0c;在平常我们实现这个功能时&#xff0c;可能大部分都是通过比对用户名和密码&#xff0c;只要正确&#xff0c;就登录成功&#xff…...

Springboot基于Redis的高性能分布式缓存数据库的实现与实例

一、引言 在现代的分布式系统和高并发应用中&#xff0c;缓存机制显得尤为重要。Redis作为一种开源&#xff08;BSD许可&#xff09;的内存键值存储&#xff0c;因其高性能、丰富的数据结构和多样化的应用场景&#xff0c;成为开发者们的首选。在这篇博客中&#xff0c;我们将…...

防止多次点击,vue的按钮上做简易的防抖节流处理

话不多说,上个视频,看看是不是你要的效果 防抖节流 1.创建一个directive.js // directive.js export default {install(Vue) {// 防重复点击(指令实现)Vue.directive(repeatClick, {inserted(el, binding) {el.addEventListener(click, () > {if (!el.disabled) {el.disabl…...

云计算【第一阶段(21)】Linux引导过程与服务控制

目录 一、linux操作系统引导过程 1.1、开机自检 1.2、MBR引导 1.3、GRUB菜单 1.4、加载 Linux 内核 1.5、init进程初始化 1.6、简述总结 1.7、初始化进程centos 6和7的区别 二、排除启动类故障 2.1、修复MBR扇区故障 2.1.1、 实验 2.2、修复grub引导故障 2.2.1、实…...

Google 发布最新开放大语言模型 Gemma 2,现已登陆 Hugging Face Hub

Google 发布了最新的开放大语言模型 Gemma 2&#xff0c;我们非常高兴与 Google 合作&#xff0c;确保其在 Hugging Face 生态系统中的最佳集成。你可以在 Hub 上找到 4 个开源模型 (2 个基础模型和 2 个微调模型) 。发布的功能和集成包括&#xff1a; Hub 上的模型https://hf.…...

智能分析赋能等保:大数据技术在安全审计记录中的应用

随着信息技术的飞速发展&#xff0c;大数据技术在各行各业中的应用愈发广泛&#xff0c;特别是在网络安全领域&#xff0c;大数据技术为安全审计记录提供了强有力的支撑。本文将深入探讨智能分析如何赋能等保&#xff08;等级保护&#xff09;&#xff0c;以及大数据技术在安全…...

Django中,update_or_create()

在Django中&#xff0c;可以使用update_or_create()方法来更新现有记录或创建新记录。该方法接受一个字典作为参数&#xff0c;用于指定要更新或创建的字段和对应的值。 update_or_create()方法的语法如下&#xff1a; 代码语言&#xff1a;python obj, created Model.obje…...

每日一学(1)

目录 1、ConCurrentHashMap为什么不允许key为null&#xff1f; 2、ThreadLocal会出现内存泄露吗&#xff1f; 3、AQS理解 4、lock 和 synchronized的区别 1、ConCurrentHashMap为什么不允许key为null&#xff1f; 底层 putVal方法 中 如果key || value为空 抛出…...

SpringMVC(1)——入门程序+流程分析

MVC都是哪三层&#xff1f;在Spring里面分别对应什么&#xff1f;SpringMVC的架构是什么&#xff1f; 我们使用Spring开发JavaWeb项目&#xff0c;一般都是BS架构&#xff0c;也就是Browser&#xff08;浏览器&#xff09;-Server&#xff08;服务器&#xff09;架构 这种架构…...

成绩发布背后:老师的无奈与痛点

在教育的广阔天地里&#xff0c;教师这一角色承载着无数的期望与责任。他们不仅是知识的传播者&#xff0c;更是学生心灵的引路人。而对于班主任老师来说&#xff0c;他们的角色更加多元&#xff0c;他们不仅是老师&#xff0c;还必须是“妈妈”。除了像其他老师一样备课、上课…...

MySQL 索引之外的相关查询优化总结

在这之前先说明几个概念&#xff1a; 1、驱动表和被驱动表&#xff1a;驱动表是主表&#xff0c;被驱动表是从表、非驱动表。驱动表和被驱动表并非根据 from 后面表名的先后顺序而确定&#xff0c;而是根据 explain 语句查询得到的顺序确定&#xff1b;展示在前面的是驱动表&am…...

EE trade:贵金属投资的优点及缺点

贵金属(如黄金、白银、铂金和钯金)一直以来都是重要的投资和避险工具。它们具有独特的物理和化学特性&#xff0c;广泛应用于各种行业&#xff0c;同时也被视为财富储备。在进行贵金属投资时&#xff0c;了解其优点和缺点对于做出明智的投资决策至关重要。 一、贵金属投资的优…...

python工作目录与文件目录

工作目录 文件目录&#xff1a;文件所在的目录 工作目录&#xff1a;执行python命令所在的目录 D:. | main.py | ---data | data.txt | ---model | | model.py | | train.py | | __init__.py | | | ---nlp | | | bert.py | …...

可信和可解释的大语言模型推理-RoG

大型语言模型&#xff08;LLM&#xff09;在复杂任务中表现出令人印象深刻的推理能力。然而&#xff0c;LLM在推理过程中缺乏最新的知识和经验&#xff0c;这可能导致不正确的推理过程&#xff0c;降低他们的表现和可信度。知识图谱(Knowledge graphs, KGs)以结构化的形式存储了…...

秋招季的策略与行动指南:提前布局,高效备战,精准出击

6月即将进入尾声&#xff0c;一年一度的秋季招聘季正在热火进行中。对于即将毕业的学生和寻求职业发展的职场人士来说&#xff0c;秋招是一个不容错过的黄金时期。 秋招的序幕通常在6月至9月间拉开&#xff0c;名企们纷纷开启网申的大门。在此期间&#xff0c;求职备战是一个系…...

Java并发编程-wait与notify详解及案例实战

文章目录 概述wait()notify()作用注意事项用wait与notify手写一个内存队列wait与notify的底层原理:monitor以及wait_setMonitor(监视器)Wait Set(等待集合)Wait() 原理Notify() / NotifyAll() 原理注意事项wait与notify在代码中使用时的注意事项总结案例实战:基于wait与not…...

204.贪心算法:分发饼干(力扣)

以下来源于代码随想录 class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 对孩子的胃口进行排序sort(g.begin(), g.end());// 对饼干的尺寸进行排序sort(s.begin(), s.end());int index s.size() - 1; // 从最大的饼…...

AI奥林匹克竞赛:Claude-3.5-Sonnet对决GPT-4o,谁是最聪明的AI?

目录 实验设置 评估对象 评估方法 结果与分析 针对学科的细粒度分析 GPT-4o vs. Claude-3.5-Sonnet GPT-4V vs. Gemini-1.5-Pro 结论 AI技术日新月异&#xff0c;Anthropic公司最新发布的Claude-3.5-Sonnet因在知识型推理、数学推理、编程任务及视觉推理等任务上设立新…...

【C++】const修饰成员函数

const修饰成员函数 常函数&#xff1a; 成员函数后加const后我们称为这个函数为常函数 常函数内不可以修改成员属性 成员属性声明时加关键字mutable后&#xff0c;在常函数中依然可以修改 class Animal { public:void fun1(){//这是一个普通的成员函数 }void fun2…...

基于模糊神经网络的时间序列预测(以hopkinsirandeath数据集为例,MATLAB)

模糊神经网络从提出发展到今天,主要有三种形式&#xff1a;算术神经网络、逻辑模糊神经网络和混合模糊神经网络。算术神经网络是最基本的&#xff0c;它主要是对输入量进行模糊化&#xff0c;且网络结构中的权重也是模糊权重&#xff1b;逻辑模糊神经网络的主要特点是模糊权值可…...

Java web应用性能分析之【prometheus监控K8s指标说明】

常规k8s的监控指标 单独 1、集群维度 集群状态集群节点数节点状态&#xff08;正常、不可达、未知&#xff09;节点的资源使用率&#xff08;CPU、内存、IO等&#xff09; 2、应用维度 应用响应时间 应用的错误率 应用的请求量 3、系统和集群组件维度 API服务器状态控…...

Spring Boot中的应用配置文件管理

Spring Boot中的应用配置文件管理 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨Spring Boot中的应用配置文件管理。在现代的软件开发中&am…...

SCCB协议介绍,以及与IIC协议对比

在之前的文章里已经介绍了IIC协议&#xff1a;iic通信协议 这篇内容主要介绍一下SCCB协议。 文章目录 SCCB协议&#xff1a;SCCB时序图iic时序图SCCB时序 VS IIC时序 总&#xff1a;SCCB协议常用在摄像头配置上面&#xff0c;例如OV5640摄像头&#xff0c;和IIC协议很相似&…...

K8S基础简介

用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 功能&#xff1a; 服务发现和负载均衡&#xff1b; 存储编排&#xff1b; 自动部署和回滚&#xff1b; 自动二进制打包&#xff1b; 自我修复&#xff1b; 密钥与配置管理&#xff1b; 1. K8S组件 主从方式架…...

Studying-代码随想录训练营day24| 93.复原IP地址、78.子集、90.子集II

第24天&#xff0c;回溯算法part03&#xff0c;牢记回溯三部曲&#xff0c;掌握树形结构结题方法&#x1f4aa; 目录 93.复原IP地址 78.子集 90.子集II 总结 93.复原IP地址 文档讲解&#xff1a;代码随想录复原IP地址 视频讲解&#xff1a;手撕复原IP地址 题目&#xff1…...

2024《汽车出海全产业数据安全合规发展白皮书》下载

随着中国制造向中国智造目标的迈进&#xff0c;中国汽车正以前所未有的速度和质量&#xff0c;在全球市场上开疆拓土。不过&#xff0c;在中国汽车加快出海步伐的过程中&#xff0c;数据安全合规风险管理成为车企不容忽视的课题。 6月25日&#xff0c;在中国&#xff08;上海&…...

firewalld防火墙(二)

一&#xff1a;firewalld高级配置 1&#xff1a;关于iptables的知识 iptables 是Linux系统中传统的命令行防火墙管理工具&#xff0c;它基于内核的netfilter框架工作&#xff0c;用于配置和管理网络规则集&#xff0c;比如过滤&#xff08;允许/拒绝&#xff09;进出的数据包…...

Chirp信号生成(FPGA、基于cordic IP核)

一、Chirp生成模块介绍 采用Verilog 生成Chirp&#xff0c;实现输入使能电平&#xff0c;模块输出Chirp信号&#xff0c;Chirp信号频率范围&#xff0c;时间宽度&#xff0c;连续Chirp信号数量可配置。 二、模块例化方法示例 parameter FL d20_000 ; parameter FH…...

【手撕面试题】React(高频知识点一)

每天10道题&#xff0c;100天后&#xff0c;搞定所有前端面试的高频知识点&#xff0c;加油&#xff01;&#xff01;&#xff01;在看文章的同时&#xff0c;希望不要直接看答案&#xff0c;先思考一下自己会不会&#xff0c;如果会&#xff0c;自己的答案是什么&#xff1f;想…...

【C++】多态(详解)

前言&#xff1a;今天学习的内容可能是近段时间最难的一个部分的内容了&#xff0c;C的多态&#xff0c;这部分内容博主认为难度比较大&#xff0c;各位一起慢慢啃下来。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23…...

《后端程序猿 · 基于 Lettuce 实现缓存容错策略》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;如需交流&#xff…...

docker配置redis主从复制

下载redis,复制redis.conf 主节点(6379) 修改redis.conf # bind 127.0.0.1 # 注释掉这里 protected-mode no # 改为no port 6379从节点(6380) 修改redis.conf bind 127.0.0.1 protected-mode no # 改为no port 6380 replicaof 172.17.0.2 6379 # 这里的ip为主节点容器的i…...

伊莱克斯可持续发展副总裁SarahSchaefer:可持续发展是伊莱克斯

“联合国可持续发展气候目标中有范围一和范围二的碳排放目标。在范围一及范围二(运营过程)中,我们在2022年提前三年实现了阶段性目标,与2015年相比减少了80%以上的绝对碳排放量。伊莱克斯集团运营里60%的能源是可再生能源、71%的工厂已经实现了零填埋的目标。”伊莱克斯集团欧…...

来自90年前的首款银箭赛车,梅赛德斯-奔驰W25创造无数传奇

90年前,这款银色单座赛车奠定了“银箭”这个名称,至今仍适用于梅赛德斯-奔驰的赛车。梅赛德斯-奔驰W25于1934年6月3日在纽博格林的艾菲尔赛事中首次亮相,Manfred von Brauchitsch赢得比赛,创下平均时速122.5公里的新纪录。这是成功故事的开始,延续至今天的梅赛德斯-AMG Pe…...

面对6大争议,为什么我认为乐道L60必成爆款?

5月15日,国际家庭日。乐道首场品牌发布会以及首款车型乐道L60正式亮相。预售价格为21.99万元,叠加“2000元抵扣6000元购车款”政策之后,实际预售价为21.59万元。我们就从这个问题出发,又分别列出了以下6个问题,同时我们也采访了蔚来创始人李斌和乐道品牌负责人艾铁成,对于…...

vs code中编写c++基本使用以及问题总结

vs code基本使用以及总结 launch.json作用 这个文件配置了调试器的设置&#xff0c;允许你定义如何启动和调试你的程序。这包括配置执行路径、传递给程序的参数、环境变量以及特定语言或框架的调试器选项。 常用配置 "version": "0.2.0": 这是配置文件…...

Day 6:2981. 找出出现至少三次的最长特殊子字符串 I

Leetcode 2981. 找出出现至少三次的最长特殊子字符串 I 给你一个仅由小写英文字母组成的字符串 s 。 如果一个字符串仅由单一字符组成&#xff0c;那么它被称为 特殊 字符串。例如&#xff0c;字符串 “abc” 不是特殊字符串&#xff0c;而字符串 “ddd”、“zz” 和 “f” 是特…...

解锁Android高效数据传输的秘钥 - Parcelable剖析

作为Android开发者&#xff0c;我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的"传输"往往不仅仅是简单的数据复制&#xff0c;还可能涉及跨进程的内存复制操作。当传输的数据量较大时&#xff0c;这种操作可能会带来严重的性能问题。而Android系…...