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

Linux——进程间通信1

目录

进程间通信目的

进程间通信标准

 管道

 匿名管道

管道实现进程间通信

管道的特点 

 进程池

ProcessPool.cc 

Task.hpp 

习题 


进程间通信目的

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

进程间通信不是目的,是手段。

 技术背景

1.进程是具有独立性的,虚拟地址空间+页表保证进程允许的独立性(进程内核数据结构+进程的代码和数据)

2.通信成本会比较高

进程间通信的本质理解

1.进程间通信的前提,首先需要让不同的进程看到同一块“内存”(特定的结构组织的)

2.这个所谓的“内存”不属于任何一个进程,强调的是共享

进程间通信标准

1.Linux原生能提供——管道(匿名,命名)

2.SystemV——多进程——单机通信

SystemV有共享内存,消息队列,信号量

3.posix——多线程——网络通信 

 这些标准在使用者看来,都是接口上具有一定的规律。

 管道

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

只要是管道就一定有出口和入口,但是出入口数量有n种可能,单向传输内容,管道是用来传资源的。计算机的设计者,设计了一种单向通信模式——管道。

 

 管道通信背后是进程之间通过管道进行通信

 每个进程都有一个自己的文件描述符表,进程内部有files*指针,指向自己的文件描述符表,文件描述符表都有自己的数组下标,0,1,2是标准输入,标准输出,标准错误流,linux下一切皆文件,没个文件都有自己的struct_file结构,struct_file不仅包含inode属性,也包含文件对应的内核缓冲区,这个缓冲区在内核中对应的结构叫address_space

 

1. 我们以读和写的方式打开同一个文件,给父进程返回的时候会返回俩个文件描述符

 2.fork()创建子进程

由于进程具有独立性,子进程会有自己的task_struct和文件描述符表,之后父进程相关的数据会拷贝给子进程,文件描述符表也会拷贝给子进程。

这样不同的进程看到同一份资源(内存),这里这是创建了子进程,我们的目的是子进程,不会拷贝文件相关数据结构,只会拷贝进程相关数据结构。

 

 管道的底层原理就是以文件的形式设计

3.双方进程各自关闭自己不需要的文件描述符。

由于管道是单向通信,我们目前规定父进程写入,子进程读取。

这就叫管道 ,管道就是文件,俩个进程通过文件来进行通信

 

 当我们在上面操作的文件中写入了数据,没必要把这些数据刷新到磁盘中,进程间通信要保证纯内存级别的通信,磁盘是外设。

 匿名管道

 #include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);

输出型参数,期望通过调用它,得到被打开的文件fd,创建成功时返回值为0,失败返回值为-1。

谁调用pipe,就让谁以读写方式打开文件,不需要指定文件名,这个文件是纯内存级别的,如struct_file就不在磁盘中。文件属于内核,一个进程把文件给操作系统,然后另一个进程通过操作系统去读取。
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

 用代码进行测试

 

 进行调试

 

 

 如果要不想调试

 在-DDEBUG前面加#

 此时结果不能打印

我们接下来要实现让父进程写入,子进程读取。

 创建子进程,并进行读写通道的建立

 read的返回值类型是ssize_t这是long int

snprintf,把特定的字符串内容显示到字符串中

管道实现进程间通信

#include<iostream>
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<assert.h>
#include<string>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
int main()
{int pipefd[2]={0};//默认设置为0int n=pipe(pipefd);//完成了管道的创建,默认以读写方式打开//断言在DEBUG模式下有效,release无效//如果没有(void)n n就只被定义而未被使用,可能会在 Realse模式下会出现大量的警告,所以我们加了(void)n
assert(n!=-1);
(void)n;
//查看读和写对应的文件描述符
#ifdef DEBUGcout << "pipefd[0]: " << pipefd[0] << endl; // 3 读端cout << "pipefd[1]: " << pipefd[1] << endl; // 4 写端
#endif//2.创建子进程pid_t id=fork();assert(id!=-1);if(id==0){//子进程//3.构建单向通信的信道// 3.1关闭子进程不需要的fdclose(pipefd[1]);//子进程关闭写端char buffer[1024];while(true){ssize_t s= read(pipefd[0],buffer,sizeof(buffer)-1);//从读端进行读,将内容读取到buffer中,大小为buffer-1if(s>0)//读取成功{buffer[s]=0;//由于是系统层面的读取,没有\0,所以我们在这添加\0cout<<"child get a message["<<getpid()<<"]Father# "<<buffer<<endl;//打印来自父进程的文件内容}}exit(0);}//父进程//3.构建单向通信的信道//3.1关闭父进程不需要的fdclose(pipefd[0]);//父进程关闭读端string message="我是父进程,我正在给你发消息";int count=0;//计数器,统计发送消息的条数char send_buffer[1024];//要发送的缓冲区while(true){//3.2 构建一个变化的字符串snprintf(send_buffer,sizeof(send_buffer),"%s[%d]:%d",message.c_str(),getpid(),count++);//把消息和统计次数格式化到缓冲区当中//3.3 写入write(pipefd[1],send_buffer,strlen(send_buffer));//把缓冲区的内容写入到写端,这里的strlen后面不需要+1//因为管道也是文件,不需要给文件描述符对应的文件写入\0,因为没意义//3.4 故意sleepsleep(1);}//等待子进程pid_t ret=waitpid(id,nullptr,0);assert(ret<0);(void)ret;close(pipefd[1]);//结束之后,关闭写端,子进程不需要写,因为子进程程序中有exit(0),当推出后,文件描述符会被关掉,此时文件不一定被释放。文件是父进程打开的,当父进程结束时,文件会被释放return 0;}

我们在程序里写端缓冲区有一个buffer,读端缓冲区也有一个buffer, 不用全局buffer是因为有写时拷贝的存在,父子进程要确保自己数据的私有性,再怎么定义全局变量,也无法进行通信。

管道的特点 

 1.管道是用来进行具有“学院”关系的进程进行进程间通信——常用于父子通信

管道是一个文件,显示器也是一个文件,父子同时往显示器写入的时候,如果没有先后顺序俩个同时写入,这种情况是由于缺乏访问控制。

管道文件,在进行读取的时候,子进程会等待父进程,如这里休眠10s,在休眠的这段时间,子进程一直都在等父进程,所以显示器未打印数据,这叫具有访问控制

2.管道具有通过让进程间协同,提供了访问控制

不控制父进程的写入速度,让子子进程20s后再读

 

程序一执行,管道就被写满 

 

之后子进程进行读取,一次性把管道里的内容读取完

子进程读取完之后,父进程又开始写,直到写满

 3.管道提供的时面向流式的服务——面向字节流一般需要定制协议

 4.管道是基于文件的,文件的生命周期时随进程的,管道的生命周期是随进程的(如果父子进程在使用管道通信,通信双方退出,管道会被自动释放)

如果读的时候,写入的一方的fd没有关闭,如果有数据就读,没有数据就等,如果写入的一方fd关闭,读取的一方,read会返回0,表示读到了文件的结尾

写了10次,关闭写端

 写入端关闭,子进程 退出

5.管道是单向通信的,就是半双工通信的一种特殊情况(要么一者在接收,要么一者在发送)。 全双工(俩人吵架,俩人同时在说,同时在听)。

 a.写快,读慢,写满就不能再写了

b.写慢,读快,管道没有数据的时候,就必须等待

c.写关,读到了0(读到文件结尾,即把所有文件读取完),表示读到了文件结尾

d.读关,写继续写,OS终止写进程

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性(只有做和不做俩种选择)。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
 

 进程池

 每个子进程和父进程形成一个管道,0是fd为0,1是fd为1,当用户要父进程完成任务时,父进程可指派子进程进行完成,可随机选子进程或按照某种特定顺序让子进程执行。

我们在这里让父进程每次写4字节,子进程读四字节

ProcessPool.cc 

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task.hpp"#define PROCESS_NUM 5//进程个数
using namespace std;
int waitCommand(int waitFd,bool &quit)
{//uint32_t是4个字节uint32_t command=0;ssize_t s=read(waitFd,&command,sizeof(command));//从waitFd里读取内容到command,大小为4个字节if(s==0)//此时把文件描述符关了{quit=true;return -1;}assert(s==sizeof(uint32_t));return command;//返回读到的命令
}void sendAndWakeup(pid_t who, int fd, uint32_t command)
{//给who进程通过fd发送command命令write(fd, &command, sizeof(command));cout << "main process: call process " << who << " execute " << desc[command] << " through " << fd << endl;
}
int main()
{load();vector<pair<pid_t,int>> slots;//pair的first是pid,second是进程相关信息pipefd//slots是一个表,表里存的是子进程的id和pipefd,父进程可以通过该表选择让哪个子进程执行任务//创建多个进程for(int i=0;i<PROCESS_NUM;++i){int pipefd[2]={0};//创建管道int n=pipe(pipefd);assert(n==0);pid_t id=fork();(void)n;assert(id!=-1);//子进程让他进行读取if(id==0){//子进程//关闭子进程写端close(pipefd[1]);while(true){bool quit=false;//一开始先不退出,后面要等待命令int command=waitCommand(pipefd[0],quit);//子进程等命令,在读取文件描述符那里等命令,如果对方不发命令,我们就阻塞if(quit)break;//执行对应的命令if(command>=0&&command<handlerSize())//如果范围之类{callbacks[command]();//直接调用对应的方法}else{cout<<"非法command"<<command<<endl;}}exit(1);}//父进程close(pipefd[0]);slots.push_back(pair<pid_t,int>(id,pipefd[1]));//子进程ID,写端描述符//把所有的子进程信息,放到vector里,形成一张子进程表}//整个for循环就是在选择父进程在选择子进程,并且准备给子进程发指令//父进程派发任务,用单机版的负载均衡(防止出现一个子进程做多个任务,均衡一下子进程工作量)//我们用随机数派发srand((unsigned long)time(nullptr)^getpid()^2323232323L);//让数据源更随机while(true){cout<<"########################################"<<endl;cout<<"#  1.show functions   2.send command   #"<<endl;cout<<"########################################"<<endl;cout<<"Please Select";int select;int command;//命令cin>>select;if(select==1)//显示可以被执行的任务{showHandler();}else if(select==2)//发送命令{//选择任务cout<<"Enter Your Command";cin>>command;//输入命令//选择进程int choice=rand()%slots.size();//布置任务,把任务给指定的进程sendAndWakeup(slots[choice].first,slots[choice].second,command);//发送命令并且唤醒子进程}else{}}//关闭fd,结束所有进程for(const auto slot:slots){close(slot.second);}//回收所有的子进程信息for(const auto slot:slots){waitpid(slot.first,nullptr,0);}return 0;
}

Task.hpp 

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unistd.h>
#include <functional>typedef std::function<void()> func;//定义一个函数类型,返回值类型void,参数()std::vector<func> callbacks;//回调
std::unordered_map<int, std::string> desc;void readMySQL()
{std::cout << "sub process[" << getpid() << " ] 执行访问数据库的任务\n" << std::endl;
}void execuleUrl()
{std::cout << "sub process[" << getpid() << " ] 执行url解析\n" << std::endl;
}void cal()
{std::cout << "sub process[" << getpid() << " ] 执行加密任务\n" << std::endl;
}void save()
{std::cout << "sub process[" << getpid() << " ] 执行数据持久化任务\n" << std::endl;
}void load()
{desc.insert({callbacks.size(), "readMySQL: 读取数据库"});//相当于构建键值对,0号命令对应readmysqlcallbacks.push_back(readMySQL);//下标为0,插入ReadMysqldesc.insert({callbacks.size(), "execuleUrl: 进行url解析"});callbacks.push_back(execuleUrl);desc.insert({callbacks.size(), "cal: 进行加密计算"});callbacks.push_back(cal);desc.insert({callbacks.size(), "save: 进行数据的文件保存"});callbacks.push_back(save);
}void showHandler()//显示当前所有的方法
{for(const auto &iter : desc ){std::cout << iter.first << "\t" << iter.second << std::endl;}
}int handlerSize()//共有多少任务的处理方法
{return callbacks.size();
}

习题 

1.以下描述正确的有:B

A.进程之间可以直接通过地址访问进行相互通信

B.进程之间不可以直接通过地址访问进行相互通信

C.所有的进程间通信都是通过内核中的缓冲区实现的

D.以上都是错误的

A错误: 进程之间具有独立性,拥有自己的虚拟地址空间,因此无法通过各自的虚拟地址进行通信(A的地址经过B的页表映射不一定映射在什么位置)

B正确

C错误: 除了内核中的缓冲区之外还有文件以及网络通信的方式可以实现 

 2.以下选项属于进程间通信的是(A,B,D)[多选]

A.管道

B.套接字

C.内存

D.消息队列

典型进程间通信方式:管道,共享内存,消息队列,信号量。 除此之外还有网络通信,以及文件等多种方式

C选项,这里的内存太过宽泛,并没有特指某种技术,错误。

3.下列关于管道(Pipe)通信的叙述中,正确的是(C)

A.一个管道可以实现双向数据传输

B.管道的容量仅受磁盘容量大小限制

C.进程对管道进行读操作和写操作都可能被阻塞

D.一个管道只能有一个读进程或一个写进程对其操作

A错误 管道是半双工通信,是可以选择方向的单向通信

B错误 管道的本质是内核中的缓冲区,通过内核缓冲区实现通信,命名管道的文件虽然可见于文件系统,但是只是标识符,并非通信介质

C正确 管道自带同步(没有数据读阻塞,缓冲区写满写阻塞)与互斥

D错误 多个进程只要能够访问同一管道就可以实现通信,不限于读写个数

4.以下关于管道的描述中,正确的是 [多选]B,D

A错误,匿名管道只能用于具有亲缘关系的进程间通信,命名管道可以用于同一主机上的任意进程间通信

B正确

C错误,匿名管道需要在创建子进程之前创建,因为只有这样才能复制到管道的操作句柄,与具有亲缘关系的进程实现访问同一个管道通信

D正确

5.以下关于管道的描述中错误的是  [多选]B,C

A.可以通过int pipe(int pipefd[2])接口创建匿名管道,其中pipefd[0]用于从管道中读取数据

B.可以通过int pipe(int pipefd[2])接口创建匿名管道,其中pipefd[0]用于向管道中写入数据

C.若在所有进程中将管道的写端关闭,则从管道中读取数据时会返回-1;

D.管道的本质是内核中的一块缓冲区;

  • 管道本质是内核中的一块缓冲区,多个进程通过访问同一块缓冲区实现通信。
  • 使用int pipe(int pipefd[2])接口创建匿名管道,pipefd[0]用于从管道读取数据,pipefd[1]用于向管道写入数据。
  • 管道特性:半双工通信,自带同步与互斥,生命周期随进程,提供字节流传输服务。
  • 在同步的提现中,若管道所有写段关闭,则从管道中读取完所有数据后,继续read会返回0,不再阻塞;若所有读端关闭,则继续write写入会触发异常导致进程退出

根据以上管道理解分析:A正确,B错误,C错误,D正确

因为题目为选择错误选项,因此选择B和C选项

相关文章:

Linux——进程间通信1

目录 进程间通信目的 进程间通信标准 管道 匿名管道 管道实现进程间通信 管道的特点 进程池 ProcessPool.cc Task.hpp 习题 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件…...

循环语句——“Python”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是Python中的循环语句呀&#xff0c;分为while循环和for循环&#xff0c;下面&#xff0c;让我们进入循环语句的世界吧 循环语句 while循环 for循环 continue和break 循环语句小结 人生重开模拟器 设置初始属性 设置性别…...

Python synonyms查找中文任意词汇的同义词近义词

Python synonyms查找中文任意词汇的同义词近义词 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 一、安装 对于非专业的开发人员来说可以简单的使用Python一行代码来找到同义词。这…...

三分钟了解http和https

对应测试人员都会听过http请求和响应.在这里给大家介绍http相关的知识 一.http和https基本概念 HTTP&#xff1a;是互联网上应用最为广泛的一种网络协议&#xff0c;是一个客户端和服务器端请求和应答的标准&#xff08;TCP&#xff09;&#xff0c;用于从WWW服务器传输超文本…...

docker应用:搭建私有云盘

简介&#xff1a;NextCloud是一个开源的云存储解决方案&#xff0c;可以在自己的服务器上搭建个人云存储系统。它提供了与市面上主流云存储服务&#xff08;如Dropbox、Google Drive&#xff09;相似的功能&#xff0c;包括文件存储、共享、同步、协作等。NextCloud的主要优势在…...

【C++进阶】面向对象

程序 编写程序是为了让计算机解决现实生活中的实际问题。pascal之父、结构化程序设计先驱Niklaus Wirth提出程序 算法 数据结构。程序是完成一定功能的一些列有序指令的集合。指令 操作码 指令。将指令按一定的顺序进行整合&#xff0c;就形成了程序。 机器语言与汇编语言…...

从ChatGPT与New Bing看程序员为什么要学习算法?

文章目录为什么要学习数据结构和算法&#xff1f;ChatGPT与NEW Bing 的回答想要通关大厂面试&#xff0c;就不能让数据结构和算法拖了后腿业务开发工程师&#xff0c;你真的愿意做一辈子CRUD boy吗&#xff1f;对编程还有追求&#xff1f;不想被行业淘汰&#xff1f;那就不要只…...

SpringBoot-实用开发篇

SpringBoot开发实用篇开发实用篇中因为牵扯到SpringBoot整合各种各样的技术&#xff0c;所以在整合每一个技术之前&#xff0c;都会做一个快速的普及&#xff0c;这样的话内容整个开发实用篇所包含的内容就会比较多。在学习的时候&#xff0c;如果对某一个技术不是很清楚&#…...

Python进阶-----高阶函数->filter() 函数

目录 前言&#xff1a; filter() 函数介绍 filter() 函数使用示例 1.与循环对比 2.与lambda函数综合使用 3.使用None过滤False 4.过滤字典相关数据 前言&#xff1a; 家人们&#xff0c;当你们获取了一个序列的时候&#xff0c;想要把一些内容去掉&#xff0c;保留一部分…...

C/C++面试可能会问三:指针和数组一样吗?

答案&#xff1a;不一样。 哪里不同&#xff1f; 数组名&#xff1a;数组名的值是一个指针常量&#xff0c;也就是数组第一个元素的地址。 它的类型取决于数组元素的类型&#xff1a;如果他们是int类型&#xff0c;那么数组名的类型就是“指向int的常量指针”&#xff1b;如果…...

数字经济新生态,中小企业如何发展营销数字化

五年弹指一挥间&#xff0c;中国数字经济正从尝试探索迈向快速发展&#xff0c;这一趋势&#xff0c;从今年两会的国务院机构改革、总理政府工作报告、部长通道答疑解惑、科技领域大佬提案中都能看出来。 在政府工作报告中&#xff0c;我们可以看到数字经济在不断壮大&#xff…...

【网络】https协议

&#x1f941;作者&#xff1a; 华丞臧. &#x1f4d5;​​​​专栏&#xff1a;【网络】 各位读者老爷如果觉得博主写的不错&#xff0c;请诸位多多支持(点赞收藏关注)。如果有错误的地方&#xff0c;欢迎在评论区指出。 推荐一款刷题网站 &#x1f449; LeetCode刷题网站 文章…...

【11】SCI易中期刊推荐——计算机方向(中科院4区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…...

STM32 OTA应用开发——通过串口/RS485实现OTA升级(方式2)

STM32 OTA应用开发——通过串口/RS485实现OTA升级&#xff08;方式2&#xff09; 目录STM32 OTA应用开发——通过串口/RS485实现OTA升级&#xff08;方式2&#xff09;前言1 环境搭建2 功能描述3 程序编写3.1 BootLoader部分3.2 APP的制作4 修改工程中的内存配置4.1 Bootloader…...

【Spring6】| Bean的生命周期(重要)

目录 一&#xff1a;Bean的生命周期 1. 什么是Bean的生命周期 2. Bean的生命周期之5步 3. Bean生命周期之7步 4. Bean生命周期之10步 5. Bean的scop&#xff08;作用域&#xff09;不同&#xff0c;管理方式不同 6. 自己new的对象如何让Spring管理 一&#xff1a;Bean的…...

【C#】单据打印方案(定义打印模板、条形码、二维码、图片、标签)

系列文章 C#项目–业务单据号生成器&#xff08;定义规则、自动编号、流水号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 C#项目–开始日期结束日期范围计算&#xff08;上周、本周、明年、前年等&#xff09; 本文链接&…...

前后端身份验证

1、web 开发模式 【】基于服务端渲染的传统 Web 开发模式 【】基于前后端分离的新型 Web 开发模式&#xff1a;依赖于 Ajax 技术的广泛应用。后端只负责提供 API 接口&#xff0c;前端使用 Ajax 调用接口的开发模式 2、身份认证 【】服务端渲染推荐使用 Session 认证机制 【】…...

【蓝桥杯嵌入式】ADC模数转换的原理图解析与代码实现(以第十一届省赛为例)——STM32G4

&#x1f38a;【蓝桥杯嵌入式】专题正在持续更新中&#xff0c;原理图解析✨&#xff0c;各模块分析✨以及历年真题讲解✨都在这儿哦&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列专栏 - 蓝…...

Matlab表示 CDF 时间值

从 CDF 纪元对象中提取日期信息。CDF 表示时间的方式与 MATLAB 不同。CDF 将日期和时间表示为自 1-Jan-0000 以来的毫秒数。这在 CDF 术语中称为纪元。为了表示 CDF 日期,MATLAB 使用一个称为 CDF 纪元对象的对象。MATLAB 还可以将日期和时间表示为日期时间值或日期序列号,即…...

基于Halcon的条码定位与识别【包含 一维码 和 二维码 】

1.针对一维码问题,先列代码: dev_update_off () dev_close_window () dev_open_window (0, 0, 600, 819, black, WindowHandle) dev_set_draw (margin) *读图 read_image (Image, 20221213-174036.png)*获取一维码区域对原图进行抠图 gen_rectangle1 (ROI_0, 2169.33, 1835.…...

每天学一点之多线程

多线程 一、相关概念 并发与并行 并行&#xff08;parallel&#xff09;&#xff1a;指多个事件任务在同一时刻发生&#xff08;同时发生&#xff09;。 并发&#xff08;concurrency&#xff09;&#xff1a;指两个或多个事件在同一个微小的时间段内发生。程序并发执行可以…...

自动化测试必会的数据驱动测试你真的学会了吗?

数据驱动测试 在实际的测试过程中&#xff0c;我们会发现好几组用例都是相同的操作步骤&#xff0c;只是测试数据的不同&#xff0c;而我们往往需要编写多次用例来进行测试&#xff0c;此时我们可以利用数据驱动测试来简化该种操作。 参数化&#xff1a; 输入数据的不同从而…...

cpp之十大排序算法

十大排序算法 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-riZ9z3wf-1678258189998)(null)] 排序算法的稳定性&#xff1a;在具有多个相同关键字的记录中&#xff0c;若经过排序这些记录的次序保持不变&#xff0c;说排序算法是稳定的。 插入排序…...

java-正装照换底色小demo-技术分享

文章目录前言java-正装照换底色小demo-技术分享01 实现思路02 效果02::01 原图:02::02 执行单元测试:02::03 效果:03 编码实现前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞…...

(枚举)(模拟)(二位前缀和)99. 激光炸弹

目录 题目链接 一些话 切入点 流程 套路 ac代码 题目链接 99. 激光炸弹 - AcWing题库 数&#xff5e;啦&#xff01;我草&#xff0c;又~在&#xff5e;水&#xff5e;字&#xff5e;数&#xff5e;啦&#xff01;我草&#xff0c;又~在&#xff5e;水&#xff5e;字&am…...

vue3+vite项目移动端适配:postcss-pxtorem和amfe-flexible

一&#xff0c;定义 postcss-pxtorem PostCSS 的一个插件&#xff0c;可以从像素单位生成 rem 单位。 amfe-flexible amfe-flexible是配置可伸缩布局方案&#xff0c;主要是将1rem设为viewWidth/10。 二&#xff0c;使用 1. 设置 viewport 在 index.html 中&#xff1a; &l…...

sin x和cos x的导数

我们都知道(sin⁡x)′cos⁡x(\sin x)\cos x(sinx)′cosx&#xff0c;(cos⁡x)′−sin⁡x(\cos x)-\sin x(cosx)′−sinx&#xff0c;但是为什么呢&#xff1f; sin⁡x\sin xsinx的导数 (sin⁡x)′lim⁡Δx→0sin⁡(xΔx)−sin⁡xΔx(\sin x)\lim\limits_{\Delta x\rightarrow 0…...

html下自动消失的提示框jQuery实现

引言 最近在找一个可以自动消失的提示框&#xff0c;找来找去&#xff0c;找到了这个&#xff1a;提示框设置_html页面提示框等待一定时间消失博主写得很好&#xff0c;可以直接复制运行出来&#xff0c;我也从中得以受益。本篇文章对这篇博客的代码做了一些小的更新&#xff…...

第27篇:Java日期处理总结(一)

目录 1、Date类 1.1 如何实例化Date对象 1.2 Date相关操作方法 1.3 如何获取当前日期...

Linux入门教程——VI/VIM 编辑器

前言 本文小新为大家带来 Linux入门教程——VI/VIM 编辑器 相关知识&#xff0c;具体内容包括VI/VIM是什么&#xff0c;VIM的三种工作模式介绍&#xff0c;包括&#xff1a;一般模式&#xff0c;编辑模式&#xff0c;指令模式&#xff0c;以及模式间转换等进行详尽介绍~ 不积跬…...

哈尔滨网络科技公司做网站/百度收录规则

WebUploader获取文件上传成功路径问题 最近在使用WebUploader的时候&#xff0c;上传文件成功&#xff0c;但是怎么也获取不到返回的图片文件成功路径&#xff0c;上传成功后&#xff0c;返回文件代码如下&#xff1a; uploader.on(uploadSuccess, function (file, response) {…...

做标识的网站 知乎/网站建设免费

我们在使用mybatics的时候&#xff0c;在我们的xml编写之中&#xff0c;偶尔会遇到Cannot find class: BaseResultMap这样的问题&#xff0c;但是我们都很清楚的看到了&#xff0c;自己确确实实的定义了这样一个BaseResultMap类&#xff0c;那么这究竟是什么样子的问题呢&#…...

帮助做问卷调查的网站/免费发布软文广告推广平台

在C#中给一个字符添加角标 //在“字符映射表”中可以查到&#xff0c;二次方和三次方对应的字符编码分别是0x00b2&#xff0c;0x00b3char s Convert.ToChar(0x00b2);MessageBox.Show("123"s.ToString());...

上海专业网站建设网站/百度搜索竞价推广

Xor and Sum 之前做过一道异或的。感觉有点眼熟&#xff0c;发现不是。由于对异或一点也不熟悉。所以直接放弃了 首先写出来几项看看。 a: 1 2 4 1 1 2 4 prex : 1 3 7 6 7 5 1 prey: 1 3 7 8 9 11 15 可以…...

wordpress 数据库类/百度新闻网

telnet命令测试服务器端口是否通的办法很多站长服务器端口并不清楚怎么测试是否通&#xff0c;下面就写一篇测试服务器端口是否正常通讯的教程。本教程以Windows本机为例&#xff0c;可测试各类操作系统的服务器。首先我们电脑上需要安装一个telnet服务&#xff0c;安装方法如下…...

响应式网站开发的理解/培训课程网站

r 输出自动生成文件我被要求为我当地大学的下一学期设计新课程。 从历史上看&#xff0c;我使用Power Point创建课程幻灯片&#xff0c;并使用Word创建实验说明。 对于幻灯片和文档&#xff0c;还有其他可能的替代方法&#xff1a; Google幻灯片 一堆JavaScript框架&#xff0…...