【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量)

2023-05-16

🐱作者:一只大喵咪1201
🐱专栏:《Linux学习》
🔥格言:你只管努力,剩下的交给时间!
图

进程间通信——共享内存 | 消息队列 | 信号量

  • 🏀共享内存
    • ⚽系统调用shmget
      • key值
    • ⚽系统调用shmctl
    • ⚽系统调用shmat和shmdt
    • ⚽共享内存的进程间通信
      • 特性
    • ⚽共享内存的内核数据结构
  • 🏀消息队列(了解)
    • ⚽系统调用
  • 🏀信号量(了解)
  • 🏀总结

system V是一种进程间通信策略,它包括共享内存,消息队列以及信号量。

🏀共享内存

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

  • 共享内存也是由操作系统维护的共享资源。

图
两个进程的PCB各自维护着一个进程地址空间。当两个进程要进行通信时:

  • 操作系统在内存中开辟一个内存块。
  • 通过两个进程的页表,将内存中的内存块映射到两个进程的进程地址空间中。
  • 此时两个进程便建立了连接。
  • 进行通信时,两个进程只需要访问自己的进程地址空间即可,操作系统会通过页表访问内存中的内存块。

所以说,共享内存就是让不同的进程,看到同一块内存块

在维持通信关系中,还涉及到几个概念:

  • 挂接:将内存中创建好的内存块映射到进程的地址空间中。
  • 去关联:不想通信时,取消进程和内存的映射关系。

注意: 去关联后,共享内存仍然存在,只是和去关联的进程没有了映射关系。

⚽系统调用shmget

图
该系统调用接口就是用来在内存中创建共享内存的。它们的参数意义非凡,下面本喵来详细解释一下。

key值

关于共享内存,首先需要理解几件事情:

  • 共享内存是专门设计的ipc方式,是用来进行进程间通信的。
  • 所有想通信的进程都可以用共享内存的方式来通信。
  • 所以操作系统中注定不止一块共享内存。

共享内存多了,就需要有一个标识,让要通信的进程找到正确的共享内存。

key值就是共享内存的标识,让想要通信的进程双方看到同一块公共资源

系统中既然存在很多个共享内存,操作系统势必要将它们管理起来,管理也是使用先描述再组织的方式
图

管理共享内存并不是在管理内存块本身,而是在管理共享内存对应的结构体:

struct shm
{
	key_t key;
	size_t size;
	//....
}

结构体类似与上面代码,包含许多共享内存的属性,最重要的是,结构体中有key值。

  • 每创建一个共享内存,就会创建一个结构体对象,并且赋一个不同的key值。
  • 所以这个key值就代表着一块唯一的共享内存。

问题又来了,怎么保证这个key值是唯一的呢?

从shmget函数的声明中可以看到,这个key值是我们传给操作系统的,也就是用我们传的key值来标定共享内存。

函数ftok()

这就需要用到另一个函数ftok(),来生成一个独一无二的key值。

图

  • pathname:文件路径名,可以随意写,一般我们都写成当前路径"."。
  • proj_id:项目ID,同样可以自定义,但是不能为0。
  • 返回值:独一无二的key值。

该函数会根据我们传的路径名和项目id值生成一个key值,具体实现是通过一些算法实现的,我们不需要在意,只需要得到key值就行。

所以,在开辟共享内存之前,必须先使用ftok函数来生成一个独一无二的key值,这样才能保证我们内存块的标识是唯一的

当两个进程通过key值和共享内存挂接起来后,就可以进行通信了。

结论:key值就是用来标识共享内存的唯一性的

size

size是用来指定开辟的共享内存是多大的,以字节为单位。

  • 一般指定的大小是4KB的整数倍。
  • 也可以是任意值。

操作系统在开辟共享内存的时候是以4KB为单位的。每次开辟的共享内存,最小也是4KB的。

  • 假设我们指定4097字节大小的共享内存,但是在内存中实际开辟的共享内存是2*4KB的。
  • 但是在使用的时候只能使用4097字节的空间,剩下的空间用户无法使用,操作系统也不会用,就浪费掉了。

所以,即使用不了那么大的空间,我们也要指定4KB的整数倍。

shmflg

这是一个标志位,和之前使用的open用法相似,也是一个int类型的数据,根据比特位不同,用法也不同。

常用的两个选项:

  • IPC_CREAT:创建共享内存,如果不存在,创建新的,如果存在,获取相关信息。
  • IPC_EXCL:无法单独使用,必须与其他标志组合使用。
    IPC_CREAT | IPC_EXCL:创建共享内存,如果不存在,则创建,如果存在,错误返回。

IPC_CREAT | IPC_EXCL是专门给用户使用的,就是为了保证创建的共享内存是一块新的内存块

返回值

图

  • 创建成功返回共享内存的标识符,注意不是key值。
  • 创建失败,返回-1。

来看看返回的值是什么样子:

图
图

  • shmid也是连续的小整数,它和文件描述符fd一样,也是让用户使用的。
  • 但是它和文件描述符代表的意义又不一样。

又存在一个问题,为什么返回的不是key值,而是shmid呢?key值也是唯一的啊。

在设计上是可以的,都是唯一的数字,用户在语言层和在系统使用的标识相同是没有问题的。

  • 如果写好了一份代码,代码中使用的是key值。
  • 当系统的底层发生了变化,key值也会变化。
  • 但是代码中的key值没有变化,此时继续使用原理的代码就会出错。

所以说,用户层使用shmid而不是key值是为了让用户层和系统层解耦

结论:shmid是供用户使用的共享内存标识符

shmget系统调用就是用来让通信双方获取同一块共享内存的。

⚽系统调用shmctl

刚刚我们使用shmget时创建了五个共享内存:

图
此时创建的5个共享内存就显示出来了。

此时,进程早已经结束了,但是共享内存还是存在,没有随进程的结束而消失。

所以说,共享内存的生命周期随内核,不随进程

如果不想要这几个共享内存了,怎么删除呢?同样有指令:

  • 指令:ipcrm -m shimd
  • 功能:删除指定shimd标识的共享内存。

图
此时所有的共享内存就被删除了,但是需要我们手动的一个个去删除。

由于指令也是shell上运行的进程,也是属于用户层,所以操作共享内存时,使用的时shmid,而不是key值。

用命令行的形式未免也太麻烦了,所以有系统调用shmctl也可以用来删除共享内存,而且是自动的。

图

  • shmid:获取共享内存后返回的标识符。
  • cmd:指定控制共享内存的方式。
  • buf:描述共享内存的数据结构指针。

cmd:IPC_RMID

删除是最常用的选项。
图
图
key值和shmid也打印了,说明共享内存创建成功了,但是使用ipcs查看时,发现什么都没有,证明shmctl将创建的共享内存删除了。

cmd:IPC_STAT

用来查看共享内存内核数据结构中的属性,不常用。
图

上图所示就是共享内存的数据结构struct_shmid_ds,也就是用来描述共享内存的数据结构,这只是其中的一部分。

该结构体的第一个成员变量是struct ipc_prem shm_prem,具体内容如红色箭头所指。可以看到,key值就在这里,共享内存就是通过它来标识唯一性的。

当cmd是IPC_STAT时,我们就可以获取到共享内存的属性:

图
此时共享内存内核数据结构中的属性信息就被我们看到了。

cmd可以传的值有很多,分别对应这不同的操作,但是最常用的还是删除。

⚽系统调用shmat和shmdt

shmat

shmat是让进程和共享内存挂接:

图

  • shmid:创建共享内存后返回的标识符。
  • shmaddr:指定共享内存映射到进程地址空间中的地址,一般设置成NULL,让系统自动来设置。
  • shmflg:不用管它是啥,直接给0。
  • 返回值:共享内存映射到进程地址空间中的地址。不成功返回-1,但是是void*类型的。

图

让该进程挂接共享内存,挂接成功打印映射到进程地址空间中的起始地址。

图
在运行的时候发现报错了,说我们没有权限,再查看共享内存,发现确实是创建了,但是共享内存的权限是0,也就是我们谁都不能访问。

解决办法就让给共享内存开发相应的权限:

图

  • 在创建共享内存的时候,让其开发对拥有者的读写权限。
  • 将0600和IPC_CREAT已经IPC_EXCL或在一起。

图
此时便挂接成功了,并且成功打印出了共享内存映射在进程地址空间中的起始地址。

shmdt

shmdt是让进程和共享内存去关联。

图

  • shmaddr:要去关联的共享内存映射在进程地址空间中的起始地址。
  • 返回值:成功返回0,不成功返回-1。

nattch值

图
在使用ipcs查看共享内存的时候,有一栏是nattch。

图
图
在进程和共享内存挂接后,查看共享内存信息,发现这个共享内存的nattch变成了1。

  • nattch:表示和这块共享内存挂接的进程数量。

图
在和共享内存挂接以后,进行10s的延时,时间到进行去关联。

图

可以看到,在计时到之前,nattch的值是1,等计时到了,nattch的值变成了0,此时就将该进程和共享内存去关联了。

注意: 去关联后,共享内存还在,只是和进程没有联系了。

共享内存方式的进程间通信,用到的系统调用为shmget,shmctl,shmat,shmdt四个。

⚽共享内存的进程间通信

使用共享内存的方式,实现进程server和client之间的通信:

  • server负责创建共享内存,删除共享内存
  • server从共享内存中读数据。
  • client向共享内存中写数据。

shmget,shmctl,shmat,shmdt四个系统调用通信双方都会使用,而且会对返回值进行严格判断,所以我们将这些共用的代码放在一个头文件中。

comm.h:

图
使用ftok生成key值,如果成功的话,返回key值,失败的话之间退出进程。

图
server方需要负责维护共享内存,所以就由它来创建,将创建的具体过程封装在一个函数里,只需要调用创建函数,传入一个key值就可以创建。

创建成功返回共享内存标识符shmid,失败的话退出进程。

图
client方只需获取共享内存的shmid即可,同样将具体实现封装,只需要调用获取函数,传入一个key值就可以,获取成功返回共享内存标识符,失败退出进程。

图
挂接共享内存时,同样将具体实现封装起来,只需要调用挂接函数,传一个shmid即可,挂接成功返回映射后的虚拟地址,失败则退出进程。

  • (long long)memp == -1L解释说明:
  • memp是一个void类型的指针,即使失败返回的-1也是void的,所以在判断时要将其强转为整形。
  • Linux是64位的机器,所以指针的大小是8个字节,所以为了不发生数据截断,需要强转成对应8个字节的long long类型。
  • 常量-1默认是int类型的,加一个后缀L成为-1L就表示这是一个long long类型的常量。
  • 此时相同类型的数据才可以进行判断。

图
将具体判断细节放在函数中,使用的时候只需要调用函数即可,不用再判断。若去关联失败则进程退出。

图
调用shmctl的具体传参细节在函数中实现,删除的时候只需要调用删除函数即可,删除失败则退出进程。

comm.h头文件中的各个函数,都是为了通信双方更方便通信而设计的。

server.cpp和client.cpp:
tu
通信双方的通信框架都是按照:

  • 获取key值
  • 创建或获取共享内存(shmget)
  • 和共享内存挂接
  • 进行通信
  • 和共享内存去关联
  • 维护方伤处共享内存

双方数据传送:

图

发送方一秒发送一次,接收方一秒接收一次。

图

  • 必须先执行server,因为server负责维护共享内存,只有共享内存创建了才能进行通信。
  • 在client没有发数据之前,server就开始读取数据了,但此时什么都没有。
  • 当client开始发送时,server才能读取到数据。

特性

图

  • 通信双方获取的key值相同
    因通信双方是通过这个key值在内存中找到同一块共享内存的,key值代表着唯一性,所以必须相同
  • 标识符shmid相同
    这个标识符和文件描述符不一样,具体是什么原因以后本喵再讲,现在只需要知道双方获取的shmid是相同的。
  • 映射的虚拟地址不同
    通信双方根据通过页表将共享内存映射到各自的进程地址空间时,除非指定地址,否则不同进程情况不同,内存使用也不同,所以得到的映射虚拟地址也不同。

图
可以看到,使用共享内存通信时,不像管道那样,通信双方是通过访问管道这个公共资源来实现数据交换的。

而是双方各自访问各自的虚拟地址就可以

  • 操作系统会通过各自的页表与共享内存建立联系。
  • 所以双方各自访问自己进程地址空间中映射的起始地址时,就相当于访问到了同一块共享内存。

这样来看,双方各自管自己的就行,不用考虑对方,所以这种通信方式比较简单。

共享内存的优势:

考虑一个问题,通信双方一方写入,一方读取,采用管道和共享内存分别发生了几次数据拷贝。

管道:

图

一共需要四次。

  • 键盘->写入端进程地址空间->管道->写出端进程地址空间->显示器

共享内存:

图
一共需要两次。

  • 键盘->共享内存(写入写出端进程地址空间)->显示器

由于共享内存在双方各自的进程地址空间中都有映射,相当于三者是一个整体。

*如果考虑用户层缓冲区的话,两种方式各自再增加两次拷贝。

当通信的数据量非常大时,共享内存的方式大大减少了拷贝次数。

  • 所以说,共享内存是所有进程间通信速度最快的

共享内存的劣势:

图
在发送方,有读取,有写入,每隔1秒发生一次。

图
在写入方,有写入,有读取,每隔3秒发生一次。

图
可以看到,结果非常混乱,两个进程想读就读,想写就写,这样就会导致数据混乱,通信的数据不准确。因为双方并不知道对方的存在。

  • 原因是共享内存通信方式没有同步和互斥机制

因为没有对公共资源的保护机制,所以就会导致通信混乱

如果非要使用共享内存的方式,可以在通信双方之间再加入管道,利用管道的互斥机制来实现共享内存的互斥。有兴趣的小伙伴可以去试试。

共享内存的特征:

  • 共享内存的生命周期随内核
  • 共享内存是所有进程间通信速度最快的的方式
  • 共享内存没有同步互斥机制,不对公共资源进行保护

⚽共享内存的内核数据结构

我们知道,操作系统中不仅有一块共享内存,它们是通过key值来进行唯一性标识的。

操作系统也要管理这些共享内存,上面本喵讲过采用的是先描述后组织的方式。

图
描述就是使用上图所示的结构体对象来描述的,该结构体中包含了共享内存的所有属性。

将这些描述共享内存的结构体对象组织成某一种数据结构,例如链表,这样操作系统就将共享内存管理起来了。

  • 数据结构中存放的是描述共享内存结构体对象的指针。

这里这个指针有点特殊:

图

  • 存放的并不是结构体struct shmid_ds对象的指针。
  • 而是它的第一个成员变量struct ipc_perm shm_perm的指针。

由于结构体的地址和结构体中第一个成员的地址在数值上相等,所以在访问结构体的时候,将第一个成员的指针强转成结构体类型的指针就可以。

🏀消息队列(了解)

消息队列的公共资源是链表结构。
通信双方不会和消息队列进行挂接,而是像管道一样,访问内存中的消息队列。

图

  • 消息队列由操作系统维护,但是由通信的某一方创建和删除
  • 通信双方都需要获取到消息队列,和共享内存一样。

当发送方有数据发送时,将数据先打包成一个节点,然后尾插到内核中的消息队列中去。

当接收方接收数据时,从队列头部开始去找所需要的节点,然后进行解包得到数据。

  • 消息队列和普通队列不一样,不是严格按照先进先出的规则。
  • 读取方可以跳过队头寻找自己需要的数据。
  • 但是相同的数据,必须先读取靠近队头的。

如上图中,当读取方需要的是香蕉,但是队头是苹果,此时就可以跳过苹果,读取香蕉,并且靠近队头的香蕉先被读取。

⚽系统调用

几乎和共享内存一样,本喵就不详细介绍了。

msgget()

图

  • key:和共享内存一样,也需要生成,是消息队列唯一性的标识符。
  • msgflg:和共享内存一样,可以是IPC_CREAT或者IPC_EXCL或者是二者的组合。
  • 返回值:返回消息队列的标识符,供用户层使用。

msgctl()

图
参数和共享内存的shmctl一样。

图
这是消息队列属性描述的结构体。

  • 第一个成员变量的类型是struct ipc_perm,变量名是msg_perm,结构类型和共享内存的一样。

只要是采用system V的通信策略,描述共享资源的结构体都是这个结构,第一个变量类型都是struct ipc_perm。

msgsnd()

tu

  • msgid:消息队列标识符
  • msgp:要发送数据所在的数组,元素类型是 struct msgbuf
  • msgsz:要发生的数据大小,以字节为单位
  • msgflg:创建标记,如果使用IPC_NOWAIT,失败就会立即返回。
    0:阻塞发送
    IPC_NOWAIT:非阻塞发送
  • 返回值:失败返回-1,成功返回0

在发送数据之前,需要先将数据进行打包:

struct msgbuf
{
	long mtype; //数据类型,必须大于0
	char mtext[1];//要发送的数据
};
  • long mtype:该值是发送方用来表明数据的所属的。
  • char mtext[1]:数组大小可以改变,和msgsend中的size是一个值。

在发送的时候,需要将数据进行打包,按照上面的规则。

msgrcv()

tu

  • msgid:消息队列标识符
  • msgp:接收的数据后要存放的地址
  • msgsz:要接收的数据大小
  • msgtype:发送方设定的数据类型标识
  • 0:读取队列中的第一条消息(不在乎当前队列头元素是什么消息类型,将他当作普通队列来处理)。
  • 大于0(约定值):读取队列中类型为msgtyp 的第一条消息。(就是读取对列元素中第一个香蕉)
  • 小于0:读取队列中最小类型小于或等于msgtyp 绝对值的第一条消息。
  • msgflg:创建标记,如果指定IPC_ NOWAIT,获取失败会立刻返回
  • 0:阻塞接收
  • NOWAIT:非阻塞接收
  • 返回值:成功返回读取数据的字节数,失败返回-1。

🏀信号量(了解)

信号量本质上就是资源计数器,能够保证多个进程之间访问临界资源,执行临界区代码时。

  • 临界资源:多个进程都可以访问到的资源(例如:同一块内存)。
  • 临界区:访问临界资源时的代码,所在区域称之为临界区。

图
如上图,将一大块公共资源划分成了多个小块的公共资源,假设一个有100个小块。

  • 这个100就是信号量,它用来计数公共资源的个数。

当进程想要访问某一小块资源的时候,首先要进行的就是申请信号量,一旦申请成功,信号量就会减1。

  • 信号量申请成功进行减一的操作称为P操作

当这个进程访问完这块小资源后,需要将资源释放,这时候信号量就会加1。

  • 是否资源后信号量进行加一的操作称为V操作

当信号量为0的时候,进程就不能再申请了

此时再来看,所有进程在访问公共资源之前,都必须申请信号量,而申请信号量的前提是所有进程都能看到同一个信号量,所以这个信号量本身就是公共资源。

既然信号量是公共资源,就必须在很多进程对它进行PV操作时保证自身的安全。

  • 试想,当一个进程正在申请,但是这个进程申请的比较慢,还有几个其他进程也在申请,但是申请的快。
  • 后面几个进程把信号量都申请完了,当第一个进程申请完成以后,发现信号量没了,此时就会出错。

当然这是一种极端情况,在PV操作的时候,可能会因为时序问题,导致信号量有中间状态,从而导致数据不一致。

所以为了保证信号量的安全性:

  • 申请信号量->计数器减1->P操作必须具有原子性
  • 释放信号量->计数器加1->B操作必须具有原子性
  • 原子性:要么不做,要做就做完。
  • 也就是,信号量有互斥机制保护,当一个进程在申请信号量的时候,其他要申请信号量的进程处于阻塞状态。

信号量的具体使用,在后面用到的时候本喵会详细讲解,在这里只需要了解这些就可以。

🏀总结

重点介绍了system V通信策略的共享内存方式,包括它的原理及应该,至于消息队列和信号量仅做了解就行,在后面用到的时候本喵会详细讲解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量) 的相关文章

  • C语言实现二分法查找

    前言 二分法查找是一种常见的查找算法 xff0c 它适用于有序数组以及有序列表的查找 它的基本思想是将要查找的值和数组中间的值进行比较 xff0c 如果中间值等于要查找的值 xff0c 则返回中间值的位置 如果中间值大于目标值 xff0c
  • 【数据结构与算法】单链表的查找和建立

    x1f525 本文由 程序喵正在路上 原创 xff0c CSDN首发 xff01 x1f496 系列专栏 xff1a 数据结构与算法 x1f320 首发时间 xff1a 2022年9月22日 x1f98b 欢迎关注 x1f5b1 点赞 x1
  • 洛谷P1786 帮贡排序

    看注释应该可以明白 xff0c 不明白可以评论 xff0c 最近一直在刷模拟题 include lt iostream gt include lt algorithm gt include lt cstring gt using names
  • 输入10个数,用冒泡法对它进行排序输出。

    include lt stdio h gt int main int a 10 i j t for i 61 0 i lt 10 i 43 43 scanf 34 d 34 amp a i for i 61 0 i lt 9 i 43 43
  • git设置用户名和邮箱地址

    因为有比赛要用到git xff0c 所以学习计划 43 1 git安装就直接个教程安装就ok了 xff0c 很简单哒 xff01 安装之后直接打开 Git Bash 打开之后是这样的 然后输入 git config list xff0c 没
  • node.js操作MySQL数据库批量插入删除数据

    node js操作MySQL数据库批量插入删除数据 传参采用数组的形式 xff0c 数组里面添加多个数组 测试插入多条数据 app get 34 addusers 34 req res 61 gt res write 34 hello wo
  • 视图的创建

    浅浅的更一篇 往下看叭 创建goods表 xff0c 并插入5条记录 mysql gt create table goods gt id int 11 primary key auto increment gt type varchar 3
  • linux c编程:Posix消息队列

    Posix消息队列可以认为是一个消息链表 有足够写权限的线程可以往队列中放置消息 有足够读权限的线程可以从队列中取走消息 在某个进程往一个队列写入消息前 并不需要另外某个进程在该队列上等待消息的到达 这跟管道和FIFO 是相反的 因为对于管
  • C++封装对MySQL的基本操作

    1 环境搭建 在这里 xff0c 我将使用vscode来搭建MySQL的编程环境 首先 xff0c 下载MySQL xff0c 配置好系统环境变量并运行MySQL数据库 接着 xff0c vscode扩展中搜索并下载MySQL 与MySQL
  • pytorch学习(1) 数据集制作

    1 数据集 数据集的制作 定义 什么是数据集 通俗来说就是包含一堆数据的集合 是进行下一步训练的必备素材资源 连数据都没有 你还分析啥啊 第一步 引入Dataset模块 span class token keyword from span
  • 新版 Alist + RaiDrive 挂载阿里云盘 Open 到本地,实现网盘本地化

    新版 Alist 43 RaiDrive 挂载阿里云盘 Open 到本地 xff0c 实现网盘本地化 1 下载 Alist 和 RaiDrive2 配置 Alist3 填写挂载路径和刷新令牌4 获取刷新令牌5 使用 RaiDrive 挂载
  • 计算企业发放的奖金根据利润提成

    要求 在右侧编辑器补充代码 实现计算企业发放的奖金根据利润提成 利润 i 低于或等于10万元时 xff0c 奖金可提成10 xff1b ii 利润高于10万元 xff0c 低于20万元时 xff0c 低于10万元的部分按10 提成 xff0
  • 数字移位(指针)(C语言)

    题目描述 有n行m列个整数 xff0c 使每一行其前面各数顺序向后移k个位置 xff0c 每一行最后k个数变成最前面的k个数 要求用指向一维数组的指针变量完成 n m和k均小于100 输入说明 输入包括n 43 1行数据 xff0c 第一行
  • 使用 Vue3 重构 Vue2 项目

    目录 前言 xff1a 一 项目整体效果展示二 项目下载使用方法三 为什么要重构项目四 重构的流程五 步骤中的 96 bug 96 以及解决方式六 未解决的问题总结 xff1a 前言 xff1a 2020年9月18日 xff0c vue3正
  • Vue3 的状态管理库(Pinia)

    目录 前言 xff1a 一 什么是 Pinai二 安装与使用pinia三 什么是 store四 state1 定义 state2 组件中访问 state 五 Getters1 定义 Getters2 在组件中使用 Getters 六 Act
  • Vue3 中生命周期的使用

    目录 前言 xff1a 一 什么是生命周期函数二 什么是 Keep Alive 组件三 生命周期函数分为几种 xff0c 分别有什么用 xff1f 1 beforeCreate2 created3 beforeMount onBeforeM
  • git 的使用方法(上 - 指令)

    目录 前言 xff1a 一 Git 是什么 xff1f 二 SVN与Git的最主要的区别 xff1f 三 Git 安装四 git 配置1 创建仓库 repository2 配置3 工作流与基本操作 五 Git 的使用流程1 仓库中创建 1
  • git 的使用方法 (下 - 远程仓库和图形化)

    目录 前言 xff1a 一 什么是协同开发二 Gitee 使用协同开发1 首先注册一个码云账号2 新建一个仓库3 根据下图把新建仓库设置为开源4 在远端合并分支的方法5 链接 git 远程6 提交 xff08 同步 xff09 远程7 远程
  • docker从私有镜像库pull/push镜像问题:Error response from daemon: Get https://xxxx.com/: x509: certificate signe...

    docker从私有镜像库pull push镜像问题 xff1a Error response from daemon Get https harbor op xxxx com v2 x509 certificate signed by un
  • Vue3 中组件的使用(上)

    目录 前言 xff1a 一 什么是组件二 注册组件1 全局注册2 局部注册 二 传递数据 父 gt 子 1 字符串数组的形式2 对象的形式 三 组件事件 子 gt 父 1 字符串数组式声明自定义事件2 子组件 触发组件事件3 父组件 监听子

随机推荐

  • Vue3 中组件的使用(下)

    目录 前言 xff1a 一 透传属性和事件1 如何 透传属性和事件 2 如何禁止 透传属性和事件 3 多根元素的 透传属性和事件 4 访问 透传属性和事件 二 插槽1 什么是插槽2 具名插槽3 作用域插槽 三 单文件组件CSS功能1 组件作
  • Vue3 中的模板语法

    目录 前言一 什么是模板语法 xff1f 二 内容渲染指令1 v text2 插值表达式3 v html 三 双向绑定指令1 v model2 v model的修饰符 四 属性绑定指令1 动态绑定多个属性值2 绑定class和style属性
  • 微信小程序基础介绍

    目录 前言 xff1a 一 什么是微信小程序二 微信小程序的发展历史三 微信小程序的优缺点四 与其他相关概念的区别与H5的区别与公众号 订阅号 服务号 企业微信的区别 五 小程序的环境六 初始化项目七 小程序单位八 导航栏配置九 模板引用十
  • 使用 uni-app 完成左滑效果

    目录 前言 xff1a 一 效果展示二 代码地址三 实现思路四 效果完成步骤1 html 代码2 js代码3 css 代码4 后台代码 总结 xff1a 前言 xff1a 左滑显示编辑 删除 或者 置顶之类的功能我们经常要实现 xff0c
  • React 入门(超详细)

    目录 前言 xff1a 一 React 简介1 什么是 React2 React 的特点3 React 高效的原因4 React 官网5 React的主要原理6 Facebook为什么要建造React 二 React 的基本使用1 基础代码
  • React 面向组件编程(上)

    目录 前言 xff1a 一 组件的基本理解和使用1 函数式组件2 类式组件3 注意事项4 渲染函数式组件标签的基本流程5 渲染类组件标签的基本流程 二 组件三大核心属性 1 xff1a state1 代码示例2 效果展示3 注意4 设置状态
  • React 面向组件编程(下)

    目录 前言 xff1a 一 受控组件与非受控组件1 受控组件2 非受控组件3 效果展示4 总结 xff1a 二 组件的生命周期1 对生命周期的理解2 生命周期的三个阶段 xff08 旧 xff09 3 生命周期的三个阶段 xff08 新 x
  • React应用(基于React脚手架)

    目录 前言 xff1a 一 使用create react app创建react应用1 什么是 react 脚手架 xff1f 2 创建 cli 脚手架方式13 创建 cli 脚手架方式24 npx 5 react脚手架项目结构6 功能界面的
  • Tesseract(识别验证码)

    Tesseract windows 下的安装及简单应用 1 Tesseract安装以及简介 阻碍我们爬虫的 有时候正是在登录或者请求一些数据时候的图形验证码 因此这里我们讲解一种能将图片翻译成文字的技术 将图片翻译成文字一般被称为光学文字识
  • POJ 2893 M × N Puzzle——八数码有解条件

    题意 xff1a 给定M N的数码图 xff0c 问能否移动到最终状态 分析 有解的判定条件可见 八数码有解条件 值得一提的是 xff0c 这道题求逆序对卡树状数组 xff0c 只能用归并排序 include lt cstdio gt in
  • 【c语言典例一】十进制的数转化为二进制和八进制

    首先 xff0c 介绍十进制转二进制的方法 xff1a 十进制整数转换为二进制整数十进制整数转换为二进制整数采用 34 除2取余 xff0c 逆序排列 34 法 具体做法是 xff1a 用2整除十进制整数 xff0c 可以得到一个商和余数
  • C语言字符个数统计

    输入一行字符 xff08 字符个数小于80 xff09 xff0c 这行字符包括小写字母 xff0c 大写字母 xff0c 数字 xff0c 空格等其他可打印符号 请统计各字母的个数 xff0c 小写字母和大写字母统计于小写字母上 xff0
  • 【STC15单片机】按键&静态数码管显示0~9

    目录 数码管工作原理 共阳极数码管段码表 共阴极数码管段码表 矩阵键盘 amp 数码管综合应用 单片机型号说明 xff1a IAP15F2K61S2 新建工程时单片机型号选择STC15F2K60S2 本开发板支持的显示器件 xff1a LE
  • 字典查询python

    有字典 dict1 61 39 赵广辉 39 39 13299887777 39 39 特朗普 39 39 814666888 39 39 普京 39 39 522888666 39 39 吴京 39 39 13999887777 39 x
  • python中的序列(列表、元组、字符串)的切片操作

    目录 一 序列 二 序列常用操作 切片 注意 演示 一 序列 序列是指 内容连续 有序 xff0c 可使用下标索引的一类数据容器 列表 元组 字符串 xff0c 均可以可以视为序列 二 序列常用操作 切片 序列支持切片 xff0c 即 列表
  • 四,面向对象 ——类与对象

    面向对象的三大特征 xff1a 封装型 xff0c 继承性 xff0c 多态性 xff08 可能有些还会说有抽象性 xff09 类 xff08 class 和对象 xff08 object 是面向对象程序设计方法中最核心的概念 面向对象的两
  • POJ - 2823 滑动窗口

    题目 xff1a 给一个长度为 NN 的数组 xff0c 一个长为 KK 的滑动窗体从最左端移至最右端 xff0c 你只能看到窗口中的 KK 个数 xff0c 每次窗体向右移动一位 找出窗体在各个位置时的最大值和最小值 思路 xff1a 网
  • C语言十进制转八进制

    输入 12 输出 14 include lt stdio h gt int main int n scanf 34 d 34 amp n int i 61 0 int a 100 int count while 1 a i 61 n 8 n
  • Docker 中,对 MySQL配置文件修改

    步骤 1 docker ps span class token punctuation span a 查看docker内的镜像 2 进入容器 docker exec it 容器ID bin bash 3 找到MySQL的配置文件 mysql
  • 【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量)

    x1f431 作者 xff1a 一只大喵咪1201 x1f431 专栏 xff1a Linux学习 x1f525 格言 xff1a 你只管努力 xff0c 剩下的交给时间 xff01 进程间通信 共享内存 消息队列 信号量 x1f3c0 共