36.Linux 应用层开发--进程间通讯

2023-05-16

最近因为项目原因耽误了一些时间,导致进程间的通讯一直没有来的及学习及整理。在我们之前学过进程相关的概念和操作,还学习了轻量级的进程的线程,在我们之后的开发和面试中,多线程,多进程开发都是非常重要的,那么进程间通讯的机制是非常重要的,那么linux中进程间有哪些通讯方式呢?接下来我们详细的开始学习一下。

目前的linux中包含很多种的通信机制,现在的进程通讯可谓是集百家之长,从各种机制中继承而来。详细的发展历程就不说了,感兴趣的可以理解一下。可以通过下面的框图大概的理解一下关系。

看到这么些通讯方式,回想到了之前的线程间通讯中也有信号量,那里面学习的信号量属于POSIX信号量中的无名信号量。

今天学习的属于system v IPC的信号量,其实这两种信号量原理上是一样的,都是用来进行同步,他们只是在实现的机制上有所不同,我们不必纠结,直接学习就可以了。

下面我们先开始UNIX 系统IPC最古老的形式的无名管道和有名管道,然后再学习system v iPC的消息队列,信号量及共享内存。

一.管道

管道有无名管道(主要用在父子进程间)和有名管道(无亲缘关系也可以)。

无名管道呢速度慢,容量有限。有名管道进程通讯都可以,只是速度也比较慢。

无名管道

1.无名管道特点:

1>它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。

2>它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。

3>它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中.

2.无名管道的读写特性:

1>读无名管道

写端存在,有数据读取,无数据阻塞

写端不存在,无数据立即返回

2>写无名管道

写无名管道,读端存在有空间写,无空间阻塞

读端不存在,管道破裂。

3.如何获取无名管道的大小

int main(){
	int pfd[2];
	pid_t pid;
	int re;
	int i;
	re = pipe(pfd);
	if(re == -1){
		perror("pipe");
		return -1;
	}
	for(i=0;i<1000000;i++){
		write(pfd[1],"a",1);
		printf("i=%d\n",i);
	}
}

一直到阻塞,就可以看出管道有多大。

4.无名管道的读写

int main(){
	int pfd[2];
	pid_t pid;
	int re;
	char buf[NUM];
	if(pipe(pfd)<0){
		perror("pipe");
		return 0;
	}
	pid = fork();
	if(pid<0){
		perror("fork");
		return 0;
	}else if(pid ==0){
	    while(1){
			stpcpy(buf,"pipe test from child");
			write(pfd[1],buf,strlen(buf));
			sleep(1);
		}
	}else{
		while(1){
			memset(buf,0,NUM);
			re = read(pfd[0],buf,NUM);
			if(re>0){
				printf("buf=%s\n",buf);
			}
		}
	}
	
}

 

有名管道

1.有名管道读写操作:

写端

int main(){
	int re;
	int fd;
	char buf[32];
	unlink("/myfifo");
	re = mkfifo("/myfifo",0666);
	if(re==-1){
		perror("mkfifo");
		return -1;
	}
	fd = open("/myfifo",O_WRONLY);
	if(fd<0){
		perror("open");
		return -1;
	}
	strcpy(buf,"fifo write test");
	while(1){
		write(fd,buf,strlen(buf));
		sleep(1);
	}
}

读端

int main(){
	int re;
	int fd;
	char buf[32];
	fd = open("/myfifo",O_RDONLY);
	if(fd<0){
		perror("open");
		return -1;
	}
	while(1){
		memset(buf,0,32);
		read(fd,buf,32);
		printf("%s\n",buf);
		sleep(1);
	}
}

二.信号

这里说的信号和我们的信号量不是一回事,信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。linux内核通过信号通知用户进程,不同的信号类型代表不同的事件,比如我们使用ctrl+C 来结束终端的运行 ,kill杀死一个进程都是信号的应用。

1.进程对信号有不同的响应方式

 缺省方式(给你信号一个默认的处理程序)

 忽略信号(忽略你给的信号)

 捕捉信号(来了信号之后,执行自己定义的代码)

2.常用的信号:

终端下,执行一个应用程序,当关闭终端的时候,终端就会发送sighup信号给应用程序

,让进程终止。

如我们使用ctrl+C 来结束终端的运行,就是sigint

kill杀死一个进程,如果杀不死可以kill -9 ,-9就是用了sigkill信号,这个信号不能被捕捉和忽略。(留了个后手,防止是病毒杀不死)可以通过kill -l查看各个数字代表的信号值。

进程的前后台切换,bg,fg等都是用信号来实现的。

3.信号的发送:

1> int  kill(pid_t pid,  int sig);

pid 接收进程的进程号:

0代表同组进程; -1代表所有进程

sig 信号类型

2>int  raise(int sig);       //给自己发信号

3>int  alarm(unsigned int seconds); //常用于超时检测

成功时返回上个定时器的剩余时间,失败时返回EOF

 seconds 定时器的时间

 一个进程中只能设定一个定时器,时间到时产生SIGALRM

4>int pause(void);

 进程一直阻塞,直到被信号中断

 被信号中断后返回-1,errno为EINTR

5>void (*signal(int signo, void (*handler)(int)))(int); typedef void (*sighandler_t)(int);

                                                  sighandler_t signal(int signum, sighandler_t handler);

成功时返回原先的信号处理函数,失败时返回SIG_ERR

signo 要设置的信号类型

handler 指定的信号处理函数: SIG_DFL代表缺省方式;

可以通过返回值恢复之前的信号的行为。

 

例1,下面的例子,当我们此时在使用ctrl+c并不会退出程序,而是执行handle程序

void handle(int sig){
	if(sig == SIGINT){
		printf("I got a ctrl+C signal\n");
	}else if(sig == SIGQUIT){
		printf("I got a quit signal\n");
	}else{
		printf("other siganl\n");
	}
}

int main(){
	signal(SIGINT,handle);
	signal(SIGQUIT,handle);	
	signal(SIGHUP,handle);	
	while(1){
		sleep(1);
	}	
}

可以通过返回值恢复之前的信号的行为。

typedef void (*sight)(int);
sight oldhandle;
int count =0;

void functh(int sig){	
	count++;
	printf("I catch ctrl+c!!!\n");
	if(count==2){
		signal(SIGINT,oldhandle);
	}	
}
int main(){
	oldhandle = signal(SIGINT,functh);
	while(1) sleep(1);
}

signal(SIGINT,SIG_DFL);也可以用SIG_DFL代表缺省值,同样可以恢复。

 

例2,子进程结束会发送SIGCHLD这个信号,当时使用wait函数进行回收,因为wait是阻塞的,但是会导致父进程无法进行自己的工作,通过signal接收子进程的信号,来处理僵尸进程,这个时候就能够解放父进程。

void asasa(int sig){
	wait(NULL);
}

int main(){
	pid_t pid;
	pid = fork();
	signal(SIGCHLD,asasa);
	if(pid<0){
		perror("fork");
	}else if(pid==0){
		sleep(10);
		exit(0);		
	}	
	while(1){
		printf("hahahah,I am free!!!!!\n");
		sleep(1);
	}
}

三.共享内存

从上面我们也知道system v IPC,然后我们就开始学习IPC对象

  • IPC 对象包含: 共享内存、消息队列和信号灯集
  • 每个IPC对象有唯一的ID
  • IPC对象创建后一直存在,直到被显式地删除
  • 每个IPC对象有一个关联的KEY

通过ipcs 查看系统中的IPC对象。

要想使用IPC对象,我们肯定是要先创建他们

1.创建一个IPC对象

key_t  ftok(const char *path,  int proj_id);

  •  成功时返回合法的key值,失败时返回EOF
  •  path  存在且可访问的文件的路径
  •  proj_id  用于生成key的数字,范围1-255。

例:

   key_t key;

   if ((key = ftok(“.”, ‘a’)) == -1) {

      perror(“key”);

      exit(-1);

   }

2.共享内存特点

  • 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
  • 共享内存在内核空间创建,可被进程映射到用户空间访问,使用灵活
  • 由于多个进程可同时访问共享内存,因此需要同步和互斥机制配合使用

3.共享内存使用步骤:

  • 创建/打开共享内存
  • 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
  • 读写共享内存
  • 撤销共享内存映射
  • 删除共享内存对象

3.1共享内存的创建

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

  • 成功时返回共享内存的id,失败时返回EOF
  •  key  和共享内存关联的key,IPC_PRIVATE 或 ftok生成
  •  shmflg 共享内存标志位  IPC_CREAT|0666
  • 创建/打开一个和key关联的共享内存,大小为1024
  • 字节,权限为0666

 例:

  key_t key;
  int shmid;
  if ((key = ftok(“.”, ‘m’)) == -1) {
     perror(“ftok”);
     exit(-1);
  }

  if ((shmid = shmget(key, 1024, IPC_CREAT|0666)) < 0) {
     perror(“shmget”);
     exit(-1);
  }

3.2共享内存的映射

include <sys/ipc.h>

 #include <sys/shm.h>

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

  •   成功时返回映射后的地址,失败时返回(void *)-1
  •   shmid   要映射的共享内存id
  •   shmaddr   映射后的地址, NULL表示由系统自动映射
    •   shmflg   标志位  0表示可读写;SHM_RDONLY表示只读

3.3 共享内存读写

例如:在共享内存中存放键盘输入的字符串

      char *addr;
      int  shmid;
      ……
      if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1) {
         perror(“shmat”);
         exit(-1);
      }
      fgets(addr, N, stdin);

3.4 撤销共享内存

int  shmdt(void *shmaddr);

  •   成功时返回0,失败时返回EOF
  •   不使用共享内存时应撤销映射
  •   进程结束时自动撤销

3.4 删除共享内存

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

  •   成功时返回0,失败时返回EOF
  •   shmid   要操作的共享内存的id
  •   cmd   要执行的操作  IPC_STAT  IPC_SET  IPC_RMID
  •   buf   保存或设置共享内存属性的地址

3.5举例,创建,共享,撤销。

记得通过ipcs查看是否创建成功。

int main(){
	key_t key;
	int shmid;
	char *addr;		
	key = ftok(".",23);
	if(key==-1){
		perror("ftok");
		return -1;
	}
	shmid = shmget(key,1024,IPC_CREAT|0666);
	if(shmid==-1){
		perror("shmget");
		return -1;
	}
	
	addr = shmat(shmid,NULL,0);
	//strcpy(addr,"this my share memeory");
	printf("get share mem=%s\n",addr);	
	shmdt(addr);
	shmctl(shmid,IPC_RMID,NULL);
}

四.消息队列

接下来学习IPC的第二大将,消息队列,属于IPC对象,肯定ipc对象的创建等是必不可少的了。

  • 消息队列是System V IPC对象的一种
  • 消息队列由消息队列ID来唯一标识
  • 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等
  • 消息队列可以按照类型来发送/接收消息

消息队列的使用:

1.打开/创建消息队列    

 int msgget(key_t key, int msgflg);

  •   成功时返回消息队列的id,失败时返回EOF
  •   key 和消息队列关联的key  IPC_PRIVATE 或 ftok
  •   msgflg  标志位  IPC_CREAT|0666

2.向消息队列发送消息  

 int msgsnd(int msgid, const void *msgp, size_t size,int msgflg);

  •   成功时返回0,失败时返回-1
  •   msgid   消息队列id
  •   msgp    消息缓冲区地址
  •   size    消息正文长度
  •   msgflg   标志位 0 或 IPC_NOWAIT

3.从消息队列接收消息   msgrcv

 int msgrcv(int msgid, void *msgp, size_t size, long msgtype,  int msgflg);

  •   成功时返回收到的消息长度,失败时返回-1
  •   msgid   消息队列id
  •   msgp   消息缓冲区地址
  •   size   指定接收的消息长度
  •   msgtype   指定接收的消息类型   
  •   msgflg   标志位   0 或 IPC_NOWAIT

4.控制消息队列

 int msgctl(int msgid, int cmd, struct msqid_ds *buf);

  •   成功时返回0,失败时返回-1
  •   msgid    消息队列id
  •   cmd    要执行的操作  IPC_STAT / IPC_SET / IPC_RMID
  •   buf   存放消息队列属性的地址

5.消息格式

  • 通信双方首先定义好统一的消息格式
  • 用户根据应用需求定义结构体类型
  • 首成员类型必须为long,代表消息类型(正整数)
  • 其他成员都属于消息正文
  • 消息长度不包括首类型 long

例:

消息队列接收

#include <linux/msg.h>
#include <string.h>
#include <stdlib.h>

typedef struct{	
	long type;
	char txt[64];
}MSG;
int msgid;

#define LEN sizeof(MSG)-sizeof(long)
void rmmsg(int sig){	
	msgctl(msgid,IPC_RMID,NULL);
	exit(0);	
}

int main(){
	
	key_t ipkey;
	int re;
	MSG msg_t;
	
    ipkey = ftok(".",23);
	if(ipkey==-1){
		perror("ftok");
		return -1;
	}
	msgid = msgget(ipkey,IPC_CREAT|0666);
	if(msgid ==-1){
		perror("msgget");
		return -1;
	}	
	signal(SIGINT,rmmsg);
	
	while(1){
		re = msgrcv(msgid,&msg_t,LEN,3,MSG_EXCEPT);
		printf("receive msg:type=%d,txt=%s\n",(int)msg_t.type,msg_t.txt);
		if(re<=0){
			break;
		}
	}
	
}

消息队列发送

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

typedef struct{
	long type;
	char txt[64];
}MSG;

#define LEN sizeof(MSG)-sizeof(long)

int main(){
	
	key_t ipkey;
	int msgid;

	MSG msg_t;
	
    ipkey = ftok(".",23);
	if(ipkey==-1){
		perror("ftok");
		return -1;
	}
	msgid = msgget(ipkey,IPC_CREAT|0666);
	if(msgid ==-1){
		perror("msgget");
		return -1;
	}
	msg_t.type = 1;
	strcpy(msg_t.txt,"msg type one");
	msgsnd(msgid,&msg_t,LEN,0);

	msg_t.type = 2;
	strcpy(msg_t.txt,"msg type two");
	msgsnd(msgid,&msg_t,LEN,0);
	
}

进行编译查看下效果:gcc -o msg_recv recv    gcc -o msc_send send     然后执行./send  此时再执行./recv就可以看到打印信息了

五.信号量

信号灯也叫信号量,用于进程/线程同步或互斥的机制,之前我们也说过与之前学的信号灯原理是相同的,只是实现方式不同。

1.信号灯的类型

  •   Posix 无名信号灯(前面线程学过)
  •   Posix有名信号灯
  •   System V  信号灯

2.信号灯的含义

  计数信号灯

3.特点:

  • System V 信号灯是一个或多个计数信号灯的集合
  • 可同时操作集合中的多个信号灯
  • 申请多个资源时避免死锁

4.信号灯使用步骤

4.1打开/创建信号灯 

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

  •   成功时返回信号灯的id,失败时返回-1
  •   key   和消息队列关联的key  IPC_PRIVATE 或 ftok
  •   nsems   集合中包含的计数信号灯个数
  •   semflg   标志位  IPC_CREAT|0666   IPC_EXCL

4.2信号灯初始化   

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

  •   成功时返回0,失败时返回EOF
  •   semid    要操作的信号灯集id
  •   semnum   要操作的集合中的信号灯编号
  •   cmd   执行的操作  SETVAL  IPC_RMID
  •   union  semun      取决于cmd

4.3 P/V操作   semop

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

  •   成功时返回0,失败时返回-1
  •   semid    要操作的信号灯集id
  •   sops    描述对信号灯操作的结构体(数组)
  •   nsops   要操作的信号灯的个数

 struct  sembuf

 {

     short  sem_num;

     short  sem_op;

     short  sem_flg;

 };

  •  semnum         信号灯编号
  •  sem_op           -1:P操作   1:V操作
  • sem_flg           0 / IPC_NOWAIT

 

删除信号灯  semctl

例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
#include <sys/sem.h>
#include <string.h>

union  semun{
	int val;
};

#define SEM_READ 0
#define SEM_WRITE 0

poperation(int index,int semid){
	struct  sembuf sop;
	sop.sem_num = index;
	sop.sem_op = -1;
	sop.sem_flg = 0;
	semop(semid,&sop,1);
	
}

voperation(int index,int semid){
	struct  sembuf sop;
	sop.sem_num = index;
	sop.sem_op = 1;
	sop.sem_flg = 0;
	semop(semid,&sop,1);	
	
}


int main(){
	
	key_t key;
	int semid;
	int shmid;
	pid_t pid;
	
	char *shmaddr;
	
	key  = ftok(".",123);
	 
	semid = semget(key,2,IPC_CREAT|0777);
	if(semid<0){
		perror("semget");
		return -1;
	}

	shmid = shmget(key,256,IPC_CREAT|0777);
	if(shmid<0){
		perror("shmget");
		return -1;
	}	
	
	union  semun myun;
	myun.val = 0;
	semctl(semid,SEM_READ,SETVAL,myun);
	
	myun.val = 1;
	semctl(semid,SEM_WRITE,SETVAL,myun);	

	pid = fork();
	if(pid<0){
		perror("fork");
		return -1;
	}else if(pid == 0){
		
		shmaddr = (char*)shmat(shmid,NULL,0);
		while(1){
			poperation(SEM_READ,semid);
			printf("getshm:%s",shmaddr);
			voperation(SEM_WRITE,semid);
		}
		
	}else{
		shmaddr = (char*)shmat(shmid,NULL,0);
		
		while(1){
			poperation(SEM_WRITE,semid);
			printf("please input char to shm:");
			fgets(shmaddr,32,stdin);
			voperation(SEM_READ,semid);
		}
		
	}

 

 

 

 

 

 

 

 

 

 

 

 

 

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

36.Linux 应用层开发--进程间通讯 的相关文章

  • NMAKE编译CTK

    NMAKE编译CTK 启动编译环境 从VC中启动命令行或通过VC提供的批处理启动命令行 xff0c 以能运行编译环境 如果装了多个VC版本 xff0c 注意使用想要的VC版本启动安装编译环境 外链图片转存失败 源站可能有防盗链机制 建议将图
  • VERILOG实现四位七段数码管显示

    filename dyp v author lyq Date 2016 3 2 9 36 Lattice XP2 17 DEMO BOARD 4位七段带小数点数码管显示控制模块 clk 50M d1 d4 d 7 dp d 6 0 ASCI
  • 网络编程一些重要的面试题

    为什么需要三次握手 xff1f 答 xff1a 三次握手的目的是 为了防止已经失效的连接请求报文段突然又传到服务端 xff0c 因而产生错误 xff0c 这种情况是 xff1a 一端 client A发出去的第一个连接请求报文并没有丢失 x
  • XILNIXSDK2018为FreeRTOS增加配置项的方法

    在安装目录下找到目录 xff1a SDK 2018 1 data embeddedsw ThirdParty bsp freertos10 xilinx v1 0 data 然后通过两个步骤来完成配置项的增加 1 编辑文件 freertos
  • STM32F系列USART的IDLE中断要注意了

    只是调用USART ClearITPendingBit之类的方法是清除不了中断标志的 xff0c 必须必须在调用USART GetITStatus之后调用 USART ReceiveData xff0c 因为IDLE被搞成了一个帧 xff0
  • STM32库USART_ITConfig的坑

    USART ITConfig只能使用一个中断标志 xff01 看看中断参数的定义 xff1a define USART IT PE uint16 t 0x0028 define USART IT TXE uint16 t 0x0727 de
  • 最强大易用的开源MODBUS库-YMODBUS,包含MASTER/SLAVE

    无论是MASTER或SLAVE xff0c 构建MODBUS应用都极其简单 xff0c 可通过设置Master为Slave的Player轻松实现MODBUS网关 项目使用C 43 43 11编写 xff0c 支持多线程 xff0c 可在WI
  • keil5 添加注释说明模板

    我们使用 Keil uvision5 编写代码时 xff0c 为了规范代码 xff0c 一般会在文件开头对本文件进行注释说明 xff0c 同时我们也会在函数的开头对函数进行说明 但 Keil5 集成开发环境中没有这些注释模板 xff0c 而
  • Putty 使用记录

    Putty 显示时间戳 需要三个软件 Putty xff0c ExtraPuTTY xff0c mtputty Putty用来提供基本功能 ExtraPuTTY用来提供时间戳功能 mtputty用于多链接多页面显示 ExtraPuTTY中的
  • 学习java方面的一点收获

    学习JAVA方面的收获 经过将近两年的时间学习java xff0c 觉得在java方面有比较大的收获 在学习和实践过程中逐渐对代码习惯 软件思维都有比较进一步的了解 java语言的纯面向对象 平台无关性是java能够得到比较多的程序开发者的
  • ROS使用catkin_make编译指定功能包

    指定要编译的功能包 xff08 多个用分号相隔 xff09 catkin make DCATKIN WHITELIST PACKAGES 61 34 需要单独编译的包名 34 但是如再次使用catkin make编译所有功能包时会出现仅仅只
  • python中_、__、__xx__(单下划线、双下划线等)的含义

    默认情况下 xff0c Python中的成员函数和成员变量都是公开的 相当于java中的public xff0c 或者OC中定义在 h文件中的公开成员变量 在python中没有public private等关键词来修饰成员函数和成员变量 为
  • 龙芯1B核心板使用alsa音频播放设置,aplay播放

    龙芯1B核心板是默认启用alsa音频工具的 只需要进行一些配置就能使用 1 先检查你的板子的alsa工具是否正常 aplay l 可以查看 xff0c 是否已正确安装音频驱动 如果正常 xff0c 能看到你的音频驱动的信息 可能会出现 xf
  • centos 64bit安装arm-none-linux-gnueabi交叉编译工具链

    xfeff xfeff yum install glibc i686在centos中安装arm none Linux gnueabi有两种方法 xff0c 一种是apt get 安装容易但是不易成功 xff0c 一种是下载压缩包或安装程序
  • 旋转矩阵和欧拉角

    欧拉角介绍 旋转可以参考两种坐标系 内部坐标系 XYZ 角度 外部坐标系 xyz 角度 不考虑参考坐标系情况下 按照旋转方式可以分为两种 Proper Euler angles z x z x y x y z y z y z x z x y
  • SIP 鉴权 & HTTP 认证

    sip 鉴权是基于摘要签名认证的 具体来说 每一个用户都有一个用户名和密码 用户名和密码在客户端和SIP 服务器的数据库中都有保存 在认证的过程中 客户端将自己的信息 用户名 密码 url 等信息 做一些复杂的MD5 或者SHA256 SH
  • ROS——TF坐标变换

    TF功能包 创建功能包 cd catkin ws src catkin creat pkg learning tf roscpp rospy tf turtlesim 如果此时依赖包已有tf xff0c 后文中CMakeLists文件中的f
  • Gazebo——仿真平台搭建(基于Ubuntu20.04)

    目录 Gazebo安装配置 创建仿真环境 仿真使用 Rviz查看摄像头采集的信息 Kinect仿真 问题解决 xff1a 1 gazebo SpawnModel Failure model name mrobot already exist
  • 单片机要学多久可以找到工作?能找到哪类的工作

    单片机学多久能工作 单片机学好了能应聘什么工作 xff1f 从事单片机开发10年 xff0c 我见证了这个行业的成长 xff0c 最明显的就是这几年的工资涨幅 大家好 xff0c 我是小哥 xff0c 10年前我还是个对前景充满憧憬的小屌丝
  • 互联网企业部分面试笔试真题以及考察知识点总结(一)

    1 static的作用 1 1用static关键字修饰的静态变量 静态变量属于类 xff0c 在内存中只有一个复制 xff0c 只要静态变量所在的类被加 载 xff0c 这个静态变量就会被分配空间 1 2 static成员方法 Java中提

随机推荐

  • 史上最全网址导航大全,让世上没有找不到的好东西

    收录的导航网址大全 好用和常用的网址几乎都在里面 个人喜欢往浏览器书签收藏夹里塞喜欢的干货和网站 xff0c 以至于收藏夹里有着几千条网址 xff0c 所以比较喜欢导航 xff0c 但是浏览器原生自带的导航又太low 所以一般自己设置打开浏
  • HTTP的认证方式之DIGEST 认证(摘要认证)

    核心步骤 xff1a 步骤 1 xff1a 请求需认证的资源时 xff0c 服务器会随着状态码 401Authorization Required xff0c 返回带WWW Authenticate 首部字段的响应 该字段内包含质问响应方式
  • 相机标定评价标准

    相机标定的实验一般根据图像数据的类型分为两种 xff1a 1 仿真实验 2 实际场景的操作性实验 目前为止 xff0c 还没有形成一套完善的用于评价相机标定方法的标准体系 xff0c 通常采用的评价准则如下 xff1a 1 标定方法是否具有
  • ubuntu下串口工具的安装与使用

    1 概述 作为一个嵌入式开发人员 xff0c 串口是开发过程中不可或缺的工具之一 xff0c window下有各种各样的串口工具 xff0c 使用起来很方便 xff0c 这里不再做过多陈述 xff0c 这里主要介绍Ubuntu 16 04
  • Ubuntu查看文件大小或文件夹大小

    Ubuntu查看文件大小或文件夹大小 一 查看文件大小 查看文件大小的命令 xff1a ls l filename 会在终端输出 xff1a rw r r 1 root root 2147483648 Mar 5 09 39 filetem
  • 结构体数据对齐

    结构体数据对齐 结构体数据对齐 xff0c 是指结构体内的各个数据对齐 在结构体中的第一个成员的首地址等于整个结构体的变量的首地址 xff0c 而后的成员的地址随着它声明的顺序和实际占用的字节数递增 为了总的结构体大小对齐 xff0c 会在
  • 2016你配得上更好地自己

    传统里我一直觉得过完春节才是一年结束的时候 xff0c 但是现在慢慢习惯阳历的计算 xff0c 2017年1月1日 xff0c 看着空间里面新年祝福和期待 xff0c 突然觉得这才是过年 2016年就这样走了 xff0c 以后我再也回不到2
  • 树莓派镜像备份与恢复文章

    在做完下属步骤以后 xff0c 需要考虑分区表 xff0c 将分区表复制到镜像里 xff0c 否则系统无法启动 xff0c 而且还要回利用gparted dev loop0以及fdisk l dev loop0等命令 xff0c 查看分区类
  • 在树莓派上将现有系统复制到新存储卡(转载 )

    在树莓派上将现有系统复制到新存储卡 xff08 转载 xff09 http www eeboard com bbs thread 39663 1 1 html 最初 xff0c 使用树莓派的时候 xff0c 也许也只是为了新鲜 xff0c
  • 【c/c++】单链表、头指针、头结点、首元节点

    链表中第一个结点的存储位置叫做头指针 xff0c 那么整个链表的存取就必须是从头指针开始进行了 之后的每一个结点 xff0c 其实就是上一个的后继指针指向的位置 这里有个地方要注意 xff0c 就是对头指针概念的理解 xff0c 这个很重要
  • VINS-mono学习总结

    Vins mono是一个后端基于非线性优化的 单目与IMU紧耦合的融合定位算法 整体 xff1a 1 预处理模块 视觉 xff1a 特征点提取与追踪 IMU xff1a 惯性解算与误差状态分析 计算预积分量 2 初始化模块 xff08 旋转
  • Fast-lio个人总结

    Lidar第一帧作为基坐标 1 lidar原始数据预处理默认不提取特征 xff0c 对原始数据间隔式 xff08 间隔3个点 xff09 降采样提取 2 imu初始化 惯性解算 误差分析 状态 协方差预测 3 Lidar与imu时间状态对齐
  • 在rviz中使用键盘控制burger

    启动语句 roslaunch turtlebot3 fake turtlebot3 fake launch 启动rviz 话题通信 roslaunch turtlebot3 teleop turtlebot3 teleop key laun
  • shell脚本中=左右的空格问题

    赋值语句等号两边不能有空格 xff1a i 61 1 或i 61 i 43 1 而字符串比较 xff0c 等号两边必须有空格 if a 61 b 比较时 xff0c if a xxx b 中括号前后一定要加空格否则会报错xxx 61 eq
  • freertos.axf: Error: L6218E: Undefined symbol xTaskGetSchedulerState (referred from delay.o).

    今天移植了一下FreeRTOS xff0c 出现了freertos axf Error L6218E Undefined symbol xTaskGetSchedulerState referred from delay o xff0c 这
  • vnc桌面配置及黑屏问题解决

    一 vnc桌面配置 登入需要远程帐号下修改 vnc xstartup 如配置root远程桌面 vi vnc xstartup 原内容如下 xff1a xff3b x etc vnc xstartup xff3d amp amp exec e
  • 华清嵌入式--入学篇

    当初在学习嵌入式的时候 xff0c 就知道嵌入式门槛高 xff0c 需要的知识比较多 工作了4年多时间 xff0c 确实感觉还是刚入门的感觉 xff0c 焊接 调试 原理图 PCB 模电 数电 c语言 数据结构 单片机 linux等知识比价
  • 20.华清嵌入式--数据结构入门

    从今天开始正式开始学习数据结构与算法 从今天开始正式开始学习数据结构与算法 从上面的框图也可以从整体上把握数据结构的关键知识点 xff0c 不管是简单的顺序表还是栈 xff0c 树等 xff0c 学习的方法都是一样的他们的操作也都是无非都是
  • 35.Linux应用层开发---线程

    一 线程的概念和使用 1 线程的概念 为了进一步减少处理器的空转时间 xff0c 支持多处理器以及减少上下文切换开销 xff0c 进程在演化中出现了另外一个概念线程 它是进程内独立的一条运行路线 xff0c 是内核调度的最小单元 xff0c
  • 36.Linux 应用层开发--进程间通讯

    最近因为项目原因耽误了一些时间 xff0c 导致进程间的通讯一直没有来的及学习及整理 在我们之前学过进程相关的概念和操作 xff0c 还学习了轻量级的进程的线程 xff0c 在我们之后的开发和面试中 xff0c 多线程 xff0c 多进程开