Linux:进程间通信(二.共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)

Linux:进程间通信(二.共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)

上次结束了进程间通信一:Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)


文章目录

  • 1.System V共享内存
    • 1.1相关函数介绍
    • 写个小项目
      • 项目规划
      • Cnmm.hpp
      • ShmClient.cpp
      • PipeServe.cpp
    • 1.2指令查看与删除
  • 2.System V消息队列
      • 消息队列的原理
      • 相关函数
  • 3.System V 信号量
    • 3.1概念
    • 3.2周边知识
  • 4.内核中

1.System V共享内存

在这里插入图片描述

实现进程间通信的前提就是如何让不同的进程看到同一份资源

  • 匿名管道我们是通过子进程继承父进程打开的资源
  • 命名管道是通过两个进程都打开具有唯一性标识的命名管道文件(路径+文件名)
  • 共享内存其实是通过OS创建一块shm

System V共享内存(Shared Memory)是一种Linux中用于进程间通信(IPC)的机制。它允许多个进程访问同一块物理内存区域,从而实现数据的快速共享和交换。

  1. 原理

    • 在物理内存中申请一块内存空间作为共享内存。
    • 将这块内存空间与各个进程的页表建立映射关系,使得这些进程在虚拟地址空间中可以看到并访问这块共享内存。
    • 通过这种方式,多个进程可以像访问自己的内存一样访问共享内存,从而实现数据的快速共享和交换。
  2. 使用方式

    • 创建:使用shmget()系统调用来创建共享内存。这个函数会分配一块指定大小的内存区域,并返回一个标识符,用于后续对这块共享内存的操作。
    • 关联:使用shmat()系统调用来将共享内存关联到进程的地址空间。这个函数会将共享内存的地址告诉进程,使得进程可以通过这个地址来访问共享内存。
    • 取消关联:当进程不再需要访问共享内存时,可以使用shmdt()系统调用来取消关联。这个函数会断开进程与共享内存之间的映射关系。
    • 释放:当所有进程都不再需要这块共享内存时,可以使用shmctl()系统调用来释放它。这个函数会回收这块内存区域,并释放相关的资源。
  3. 特性:

  • 共享内存的生命周期是在进程结束后仍然存在的,直到显式地将其删除或者系统重启。这种情况下,如果进程没有主动释放共享内存,那么共享内存将一直存在于系统中,直到以下情况之一发生才会被释放:
  1. 代码删除:可以通过调用shmctl函数来删除共享内存,释放其资源。删除共享内存后,系统会立即释放共享内存的资源。
  2. 指令删除:在Linux系统中,可以使用ipcs命令查看系统中的IPC资源(包括共享内存),并使用ipcrm命令来删除特定的IPC资源
  • 共享内存是所有进程间通信中速度最快的原因

无需内核参与:在共享内存中,多个进程可以直接访问同一块物理内存区域,而无需通过内核进行数据的拷贝和传输。这样可以避免了进程间切换和内核态和用户态之间的数据拷贝,从而提高了通信的效率。

  • 共享内存并不提供进程间协同的机制,也不提供同步和互斥的功能,需要我们用户自己来实现

1.1相关函数介绍

ftok() 函数 Linux中用于生成一个唯一的键值(key)的系统调用,这个键值通常用于在进程间通信(IPC)中标识共享内存段、消息队列或信号量集。ftok() 函数基于一个已经存在的文件路径和一个非零的标识符(通常是一个小的正整数)来生成这个键值。

#include <sys/ipc.h>  
#include <sys/types.h>  key_t ftok(const char *pathname, int proj_id);

参数:

  • pathname:指向一个已经存在的文件路径的指针。这个文件通常被用作生成键值的“种子”或“基础”。
  • proj_id:一个非零的标识符,通常是一个小的正整数。这个值将与文件路径一起被用于生成键值。返回值:

如果成功,ftok() 函数返回一个唯一的键值key_t 类型),该键值可以在后续的 IPC 调用(如 shmget(), msgget(), semget() 等)中用作参数。如果失败,则返回 (key_t) -1 并设置 errno 以指示错误。

  1. shmget():创建或获取共享内存

shmget() 系统调用用于创建一个新的共享内存对象,或者如果它已存在,则返回该对象的标识符。

函数原型

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

参数

  • key:一个键,用于唯一标识共享内存对象。通常使用ftok()函数生成。

    1. 共享内存在内核中同时可以存在很多个,OS必须要管理所有的共享内存
    • 如何管理呢?先描述,在组织
    • 系统中会存在很多共享内存,怎么保证,多个不同的进程看到的是同共享内存呢? 要给共享内存提供唯一性的标识
    1. key便是那个唯一性标识符。那么为什么这个key要由我们用户来传入呢?
    • 如果然系统生成,将值返回让我们得到。那我们如何给另外一个进程呢?要做到就要有进程间通信,这不倒反天罡了?
  • size:共享内存的大小(以字节为单位)。

  • shmflg:权限标志和选项。通常设置为IPC_CREAT如果对象不存在则创建,存在的话直接获取)和权限(如0666)。

    若设置为IPC_CREAT|IPC_EXCL(如果对象不存在则创建,存在的话出错返回)

返回值:成功时返回共享内存对象的标识符;失败时返回-1并设置errno

  1. shmctl():控制共享内存

在这里插入图片描述

shmctl() 系统调用用于获取或设置共享内存的属性,或者删除共享内存对象。

函数原型

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

参数

  • shmid:共享内存对象标识符。
  • cmd:要执行的操作。例如,IPC_RMID用于删除共享内存对象,IPC_STAT用于获取其状态。
  • buf:指向shmid_ds结构的指针,用于传递或接收共享内存的状态信息。

返回值:成功时返回0;失败时返回-1并设置errno

  1. shmat():将共享内存关联到进程的地址空间

shmat() (attach)系统调用用于将共享内存对象关联到调用进程的地址空间

在这里插入图片描述

函数原型

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

参数

  • shmidshmget()返回的共享内存对象标识符
  • shmaddr:希望将共享内存附加到的进程的地址。如果设置为NULL,则系统选择地址(一般都这样)。
  • shmflg:通常设置为0或SHM_RND(使附加地址向下舍入到最接近的SHMLBA边界)。

返回值:成功时返回共享内存附加到进程的地址;失败时返回(void *)-1并设置errno

  1. shmdt():取消共享内存的关联

在这里插入图片描述

shmdt() 系统调用用于取消之前通过shmat()附加到进程的共享内存的关联。

函数原型

int shmdt(const void *shmaddr);

参数

  • shmaddrshmat()返回的共享内存附加到进程的地址。

返回值:成功时返回0;失败时返回-1并设置errno

写个小项目

项目规划

在这里插入图片描述

  • Cnmm.hpp:函数的声明定义,头文件的包含、宏定义等任务
  • ShmClient.cpp:客户端,
  • ShmServer.cpp:服务端(服务器)

makefile:

.PHONY:all
all:shm_client shm_servershm_server:ShmServer.ccg++ -o $@ $^ -std=c++11
shm_client:ShmClient.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f shm_client shm_server

Cnmm.hpp

#pragma once#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>using namespace std;const char *pathname = "/home/zc/study/lesson26/5.4_shm_ipc";
const int proj_id = 0x1;
const int defaultsize = 4096; // 单位是字节key_t GetShmKeyOrDie()
{key_t key = ftok(pathname, proj_id);if (key == -1){cerr << "ftok error, errno : " << errno << ", error string: " << strerror(errno) << std::endl;exit(1); // 出错就直接退出}return key;
}int CreateShmOrDie(key_t key, int size, int flag)
{int shmid = shmget(key, size, flag);if (shmid < 0){std::cerr << "shmget error, errno : " << errno << ", error string: " << strerror(errno) << std::endl;exit(2); // 出错就直接退出}return shmid;
}int CreateShm(key_t key, int size)
{return CreateShmOrDie(key, size, IPC_CREAT | IPC_EXCL | 0666); // 没有就创建,有就报错,权限666
}int GetShm(key_t key, int size)
{return CreateShmOrDie(key, size, IPC_CREAT); // 不存在则创建,存在的话直接获取
}void DeleteShm(int shmid)
{int n = shmctl(shmid, IPC_RMID, nullptr);if (n == -1){cerr << "shmctl error" << errno << endl;}else{cout << "delete successfully" << endl;}
}void *ShmAttach(int shmid)
{void *addr = shmat(shmid, nullptr, 0);if ((long long int)addr == -1){std::cerr << "shmat error" << std::endl;return nullptr;}return addr;
}void ShmDt(void *addr)
{int n = shmdt(addr);if (n < 0){cerr << "shmdt error" << endl;}
}

ShmClient.cpp

#include "Comm.hpp"int main()
{// 获取keykey_t key = GetShmKeyOrDie();cout << "key:" << key << endl;// 获取shmidint shmid = GetShm(key, defaultsize);cout << "shmid:" << shmid << endl;// 进行挂接void *tem = ShmAttach(shmid);char *addr = (char *)tem;cout << "Attch successfully" << endl;// 进行通信,这里进行写入for (char ch = 'A'; ch <= 'Z'; ch++){addr[ch - 'A'] = ch;}// 取消挂接ShmDt(tem);return 0;
}

PipeServe.cpp

#include "Comm.hpp"
#include <unistd.h>int main()
{// 获取keykey_t key = GetShmKeyOrDie();cout << "key:" << key << endl;// 创建共享内存int shmid = CreateShm(key, defaultsize);cout << "shmid:" << shmid << endl;// 进行挂接void *tem = ShmAttach(shmid);char *addr = (char *)tem;cout << "Attch successfully" << endl;// 进行通信,这里进行读for (;;){cout << "shm content: " << addr << std::endl;}// 取消挂接ShmDt(tem);// 删除共享内存sleep(50);DeleteShm(shmid);return 0;
}

1.2指令查看与删除

  1. 使用ipcs命令查看系统中的共享内存:
ipcs -m

显示的以下内容:

  1. 键值 (key):共享内存段的键值,用于唯一标识一个共享内存段。在创建共享内存段时可以指定一个键值,其他进程可以通过这个键值来访问同一个共享内存段。
  2. shmid:共享内存段的标识符,是系统为每个共享内存段分配的唯一标识符。其他进程可以通过 shmid 来操作同一个共享内存段。
  3. 权限 (perms):共享内存段的权限信息,包括读、写、执行权限。通常以八进制形式表示,比如 0600 表示用户具有读写权限,其他用户没有权限。
  4. 拥有者 (owner):共享内存段的拥有者,即创建该共享内存段的用户或进程。
  5. 大小 (bytes):共享内存段的大小,以字节为单位。表示该共享内存段所分配的内存空间大小。
  6. 附加进程数 (nattch):当前附加到共享内存段的进程数目。当一个进程附加到共享内存段时,nattch 数加一;当一个进程分离(detach)时,nattch 数减一。

在这里插入图片描述

  1. 使用ipcrm命令删除指定的共享内存:
ipcrm -m <shmid>

<shmid>是要删除的共享内存段的标识符。通过这个命令可以删除指定的共享内存段,释放其资源。

在这里插入图片描述

shmid与key分辨:

在共享内存的设计中,keyshmid 的使用确实是为了实现内核层和用户层之间的解耦,从而使它们在宏观层面上互不影响,具有独立性。下面详细解释一下这种设计的好处和原因:

  • 内核层使用 key 来唯一标识共享内存段,而用户层使用 shmid 来访问和操作已存在的共享内存段。这种设计使得内核层和用户层的代码逻辑相互独立,彼此不直接依赖。
  • 当内核层需要进行某些代码改动或优化时,只需在内核层处理 key 的逻辑,而不需要影响用户层的代码。用户层代码不需要关心内核层的具体实现细节,只需要通过 shmid 来操作共享内存即可。

2.System V消息队列

System V消息队列是一种进程间通信的机制,允许进程之间通过消息进行通信。消息队列提供了一个消息缓冲区,进程可以向消息队列发送消息,也可以从消息队列接收消息。下面我们来详细讲解消息队列的原理以及相关函数。

消息队列的原理

  1. 消息队列结构:消息队列是一个由内核维护的消息缓冲区,通常由消息类型和消息数据组成。每个消息都包含一个消息类型和消息数据,进程可以根据消息类型选择接收特定类型的消息。

  2. 消息发送:进程可以调用系统调用函数向消息队列发送消息,将消息写入消息队列中。发送消息时,需要指定消息队列的标识符、消息类型以及消息数据等信息。

  3. 消息接收:进程可以调用系统调用函数从消息队列接收消息,读取消息队列中的消息。接收消息时,可以选择阻塞式接收或非阻塞式接收,进程可以根据需要选择适合的接收方式。

  4. 消息类型:每个消息都有一个消息类型,进程可以根据消息类型选择接收特定类型的消息。这样可以实现不同类型的消息传递和处理。

  5. 消息队列管理:消息队列由内核管理,进程可以通过系统调用函数对消息队列进行创建、删除、发送消息、接收消息等操作。

相关函数

当使用System V消息队列相关函数时,需要了解函数的原型、参数和返回值。以下是这些函数的介绍:

  1. msggetint msgget(key_t key, int msgflg);
    • 参数key为消息队列的键值,msgflg为权限标志和操作标志的组合。
    • 返回值:成功时返回消息队列标识符,失败时返回-1并设置errno
  2. msgctlint msgctl(int msqid, int cmd, struct msqid_ds *buf);
    • 参数msqid为消息队列的标识符,cmd为控制命令,buf为消息队列信息结构体指针。
    • 返回值:成功时返回0,失败时返回-1并设置errno
  3. msgsndint msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    • 参数msqid为消息队列的标识符,msgp为消息缓冲区指针,msgsz为消息长度,msgflg为标志位。
    • 返回值:成功时返回0,失败时返回-1并设置errno
  4. msgrcvssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    • 参数msqid为消息队列的标识符,msgp为消息缓冲区指针,msgsz为消息长度,msgtyp为消息类型,msgflg为接收标志。
    • 返回值:成功时返回接收到的消息数据的长度,失败时返回-1并设置errno

3.System V 信号量

3.1概念

  1. 信号量本质:
  • 信号量通常被用来保护公共资源,确保多个进程或线程能够有序地访问和使用这些资源

  • 信号量是一个整型变量,通常用于控制对共享资源的访问。信号量的值可以表示可用资源的数量或者某个资源的占用情况

  • 信号量:信号量本质是一个计数器,描述临界资源数量的计数器

    为什么不能直接用一个int来进行呢?

    无法在进程间共享 而且一个int ++- -不是原子的

  • 信号量:公共资源中,对局部性资源进行预定的机制。可以被用于对局部性资源进行预定,实现对资源的合理分配和控制

  • 信号量是让不同的进程看到同一个计数器资源,而进程间通信是让不同的进程看到一份资源。所以信号量也属于进程间通信

进程申请信号量一旦成功:就一定有这个进程的资源了(相当于去看电影买票,一定有我们的座位了,而且别人也买不了这个座位)

当我们释放信号量后,这份资源才能给别人(看完电影后,这个座位才能接着被下一个买)

申请信号量和释放信号量来保护临界资源, 是大家都要遵守的规则(我们程序员)

  • 所有的进程,访问临界资源,都必须先申请信号量, 所有进程都得先看到同一个信号量 ==> 信号量本身就是共享资源
  1. 信号量操作:

    那谁来保护信号量呢? 通过使用原子的PV操作来保障

  • P操作(等待操作):当进程需要访问共享资源时,首先执行P操作,即尝试获取信号量。如果信号量的值大于0,则将信号量的值减1,表示资源已被占用,进程可以继续执行;如果信号量的值为0,则表示资源已被占用,进程需要等待。(允许申请多个信号量)
  • V操作(释放操作):当进程使用完共享资源后,执行V操作,即释放信号量。释放信号量会增加信号量的值,表示资源已经释放,其他进程可以继续访问。

3.2周边知识

  1. 互斥和同步:

    • 互斥:指的是在访问共享资源时,任何时刻只允许一个执行流访问,其他执行流需要等待。这样可以避免多个执行流同时修改共享资源导致数据不一致。互斥是通过使用锁或信号量等机制来实现的。(任何时候都只有一个人能访问,当信号量为1——只有一个整体资源时,不就是互斥吗)
    • 同步:指的是在访问共享资源时,具有一定的顺序性,确保多个执行流按照特定的顺序访问资源。同步可以通过信号量、条件变量等机制来实现,以确保执行流之间的协调和顺序性。
  2. 临界资源和临界区:

    • 临界资源:是指被保护起来的,任何时刻只允许一个执行流访问的公共资源。访问临界资源的代码段被称为临界区。
    • 临界区:是指访问临界资源的代码段,程序员需要在临界区内使用互斥和同步机制来确保对临界资源的安全访问
  3. 原子性:指的是操作对象的操作是不可分割的,要么整个操作完成,要么没有开始。在多线程或多进程环境中,保证操作的原子性是非常重要的,可以通过锁或原子操作等机制来实现。

  4. 保护临界区的本质:程序员需要保护临界区,确保在任何时刻只有一个执行流可以访问临界资源,避免数据竞争和不一致性。这通常通过使用锁、信号量或其他同步机制来实现。


4.内核中

内核中,所有的描述管理IPC资源的结构体,第一个成员大家都一样 kern_ipc_perm。我们可以用指针数组来进行管理

在这里插入图片描述

在内核中,对IPC资源的管理也是转变为对数组的增删查改

类型不同我们怎么解决呢?——直接强转

  • (msg_ queue*)ipc[0]> q _time;
  • (sem_array)ipc[1]->q_time;
  • (shmid kernel)ipc[2]-> 。。。

那怎么知道是什么类型呢?

kern_ipc_perm里有一个有个mode变量,能来表示类型

#define IPC TYPE SHM Ox1
#define IPC TYPE MSG (0x1<<1)
#define IPC TYPE SEM(0x1 << 2)//定义这三个宏后shmid kernel* (kern ipc_perm* p)
{if (p->mode & IPC TYPE SHM){return (shmid kernel)ipc}else if (p->mode & IPC TYPE MSG){///}else{///}
}

好啦,我也是结束了实训,才到家!!!
感谢大家的支持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++进阶:继承和多态

文章目录 ❤️继承&#x1fa77;继承与友元&#x1f9e1;继承和静态成员&#x1f49b;菱形继承及菱形虚拟继承&#x1f49a;继承和组合 ❤️多态&#x1fa77;什么是多态&#xff1f;&#x1f9e1;多态的定义以及实现&#x1f49b;虚函数&#x1f49a;虚函数的重写&#x1f499…

吴恩达机器学习作业ex8:K 异常检测和推荐系统(Python实现)详细注释

文章目录 1 异常检测1.1 高斯分布1.2 估计高斯参数1.3 选择阈值 ε1.4 高维数据集 2 推荐系统2.1 电影评分数据集2.2 协作过滤学习算法2.2.1 协同过滤成本函数2.2.2 梯度协同过滤2.2.3 Regularized cost function2.2.4 正则梯度 2.3 学习电影推荐2.3.1 推荐 后记 1 异常检测 在…

c++入门基础篇(上)

前言&#xff1a; 我们在之前学完了c语言的大部分语法知识&#xff0c;是不是意味着我们可以马上从事开发呢&#xff1f;其实行业中的绝大部分岗位都用不到c语言&#xff0c;那我们为什么要学c语言呢。c语言虽然和我们日常开发没有很大的关系&#xff0c;但是学习c语言可以为我…

14.x86游戏实战-汇编指令cmp test

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

LLm与微调

推荐尝试的微调模型 internlm2-20b-chat&#xff0c;internlm2-7b-chat&#xff0c; Qwen2-7B-Instruct, Qwen2-1.5B-Instruct, Qwen1.5-32B-Chat (Qwen2-0.5B、Qwen2-1.5B, qwen1.5的4B&#xff0c;7B&#xff0c;14B&#xff0c;32B) glm-4-9b-chat, glm-4-9b-chat-1m, gl…

SLAM相关知识

目前在SLAM上的传感器主要分为两大类&#xff1a;激光雷达和摄像头 激光雷达&#xff1a;单线、多线 摄像头&#xff1a;单目相机&#xff08;普通USB相机&#xff09;、双目相机&#xff08;2个普通的USB相机&#xff09;、单目结构光&#xff08;深度相机&#xff09;、双目…

【二】Ubuntu24虚拟机在Mac OS的VMware Fusion下无法联网问题

文章目录 1.环境背景2. 需求背景3. 解决方法3.1 在mac的终端查看虚拟机NAT网络3.2 查看unbuntu节点2的网络配置3.3 问题定位与解决3.3.1 检查是否有冲突3.3.2 冲突解决方法 4. 总结4.1 NAT 网关的原理4.2 VMware Fusion 的 NAT 模式4.3 为什么网关冲突会引起问题4.4 理解配置冲…

AutoHotKey自动热键(五)添加WINDOWS秘笈指令-输入瞬间启动功能

在AUTOHOTKEY的使用中,不仅仅可以监听组合热键,还可以监听正常文本击键录入,这是另一种监听方式,比如依次击键jsq之后直接弹出<计算器>工具,或者依次击键sj之后直接输出135****5564的手机号码,等等,这就是autohotkey的录入击键监听,以双冒号为开头:: 因这种录入监听像极了…

【UE5】仅修改结构体的若干个数据

蓝图中的结构体变量 | 虚幻引擎4.27文档 (unrealengine.com) 连线连到傻&#xff0c;因为如果某个变量set空值也一起过去了。一查发现有这个节点。

EEG源定位(EEG Source Localization)

EEG源定位&#xff08;EEG Source Localization&#xff09;是一种用于确定大脑内部电活动来源的方法。通过在头皮上记录的电信号&#xff08;EEG&#xff09;&#xff0c;源定位技术可以推断这些信号的起源&#xff0c;即确定大脑中的哪些区域产生了这些电活动。这对于理解大脑…

【面向就业的Linux的基础】从入门到熟练,探索Linux的秘密(十三)-常用的命令

上述是一些系统命令的基本练习&#xff0c;可以当做日常笔记学习收藏一下&#xff01;&#xff01;&#xff01; 目录 前言 一、文件权限 二、文件检索 三、查看文件内容 四、用户相关 五、工具 六、安装软件 七、作业​​​​​​​ 总结 前言 上述是一些系统命令的…

简单仿写MVC

代码地址&#xff08;需要自取&#xff09;&#xff1a;mvc_Imitation: 简单仿写实现MVC (gitee.com) 项目目录 先把架子搭好 Controller注解 Documented Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Controller { }RequestMapping Do…

大模型lora微调中,rank参数代表什么,怎么选择合适的rank参数

在大模型的LoRA&#xff08;Low-Rank Adaptation&#xff09;微调中&#xff0c;rank参数&#xff08;秩&#xff09;是一个关键的超参数&#xff0c;它决定了微调过程中引入的低秩矩阵的维度。具体来说&#xff0c;rank参数r表示将原始权重矩阵分解成两个低秩矩阵的维度&#…

互助学习平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;课程信息管理&#xff0c;课程分类管理&#xff0c;课程评价管理&#xff0c;学习计划管理&#xff0c;留言板管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;课程信息…

Databend 开源周报第 152 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend。 支持内置 UDFs …

数学建模美赛入门

数学建模需要的学科知识 高等数学线性代数 有很多算法的掌握是需要高等数学和线代的相关知识 如&#xff1a;灰色预测模型需要微积分知识&#xff1b;神经网络需要用到导数知识&#xff1b;图论和层次分析法等都需要用到矩阵计算的相关知识等&#xff1b; 概率论与数理统计&am…

忘记Apple ID密码怎么退出苹果ID账号?

忘记Apple ID密码怎么退出账号&#xff1f;Apple ID对每个苹果用户来说都是必不可少的&#xff0c;没有它&#xff0c;用户就不能享受iCloud、App Store、iTunes等服务。苹果手机软件下载、丢失解锁、恢复出厂设置等都需要使用Apple ID。如果忘记Apple ID 密码&#xff0c;这会…

Flutter 开启混淆打包apk,并反编译apk确认源码是否被混淆

第一步&#xff1a;开启混淆并打包apk flutter build apk --obfuscate --split-debug-info./out/android/app.android-arm64.symbols 第二步&#xff1a;从dex2jar download | SourceForge.net 官网下载dex2jar 下载完终端进入该文件夹&#xff0c;然后运行以下命令就会在该…

分享五款软件,成为高效生活的好助手

​ 给大家分享一些优秀的软件工具,是一件让人很愉悦的事情&#xff0c;今天继续带来5款优质软件。 1.图片放大——Bigjpg ​ Bigjpg是一款图片放大软件&#xff0c;采用先进的AI算法&#xff0c;能够在不损失图片质量的前提下&#xff0c;将低分辨率图片放大至所需尺寸。无论…

Windows10 企业版 LTSC 2021发布:一键点击获取!

Windows10企业版 LTSC 2021是微软发布的长达5年技术支持的Win10稳定版本&#xff0c;追求稳定的企业或者个人特别适合安装该系统版本。该版本离线制作而成&#xff0c;安全性高&#xff0c;兼容性出色&#xff0c;适合新老机型安装&#xff0c;力求带给用户更稳定、高效的操作系…