【Linux系统编程】06:共享内存

news2024/11/27 12:41:01

共享内存


OVERVIEW

  • 共享内存
      • 一、文件上锁flock
      • 二、共享内存
        • 1.关联共享内存ftok
        • 2.获取共享内存shmget
        • 3.绑定共享内存shmat
        • 4.绑定分离shmdt
        • 5.控制共享内存shmctl
      • 三、亲缘进程间通信
        • 1.共享内存写入与读取
        • 2.共享内存解绑与删除
        • 3.共享内存综合
      • 四、非亲缘进程间通信
        • 1.通过sleep同步
        • 2.通过条件变量同步

一、文件上锁flock

可以利用flock系统调用实现,当有一个进程在文件中进程写入操作时,其他进程无法在该文件中进行写操作(只能进行读操作)。

  • 多进程实现前n项数求和(利用flock实现)
#include "head.h"

struct data {
	int now;//中间结果
	int sum;//求和结果
};

void getnum(struct data *d) {
	int fd;
	if ((fd = open(".data", O_RDONLY)) < 0) {
		perror("setopen");
		exit(1);
	}
	read(fd, (void *)d, sizeof(struct data));
	close(fd);
}

void setnum(struct data *d) {
	int fd;
	if ((fd = open(".data", O_RDWR | O_CREAT, 0600)) < 0) {//只有文件的所属用户(当前的进程)有访问以及写的权限
		perror("getopen");
		exit(1);
	}
	write(fd, (void *)d, sizeof(struct data));
	close(fd);
}

void doSum(struct data *d, int max, int i) {
	int fd_lock;
	//将lock标志给到某个文件上(.lock) 通过该文件判断进程是否有资格打开另一个被保护的文件(.data)
	if ((fd_lock = open(".lock", O_RDONLY)) < 0) {
		perror("lockopen");
		exit(1);
	}
	while (1) {//计算的过程需要上锁
		flock(fd_lock, LOCK_EX);//加锁(加锁后其他进程后面计算的语句将无法执行)
		getnum(d);//从.data取出上个结果
		if (d->now >= max) break;//判断 计算结果
		d->now++;
		d->sum += d->now;
		setnum(d);//将计算的结果放回.data
		printf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);
		flock(fd_lock, LOCK_UN);//为解锁
	}
	close(fd_lock);
}

int main(int argc, char *argv[]) {
	//多进程实现求前n项和 同一时刻只有一个进程持有该文件
	//计算从0到n的和 m个进程
	//a.out -i -n n
	int opt;
	int ins = 1, max = 100;
	struct data d;
	d.now = 0;
	d.sum = 0;
	setnum(&d);
	while ((opt = getopt(argc, argv, "i:n:")) != -1) {
		switch (opt) {
		case 'i':
			ins = atoi(optarg);
			break;
		case 'n':
			max = atoi(optarg);
			break;
		default:
			fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);
			exit(1);
		}
	}
	int i;
	pid_t pid;
	for (i = 0; i < ins; ++i) {//创建ins个进程对文件进行doSum操作
		if ((pid = fork()) < 0) {
			perror("fork()");
			exit(1);
		}
		if (pid == 0) break;
	}
	if (pid == 0) {
		doSum(&d, max, i);
	} else {
		for (int k = 0; k < ins; ++k) wait(NULL);
	}
	return 0;
}

image-20230224210120883

二、共享内存

允许两个或多个进程共享一个给定的存储区,由于无需复制数据,这是最快的IPC进程间通信。

1.关联共享内存ftok

image-20230224215755103

#include "head.h"

int main() {
	//ftok将projectId与文件名字转换为键值对
	key_t key;
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	printf("key = 0x%x\n", key);
	printf("123 = 0x%x\n", 123);
	return 0;
}

image-20230224215900200

2.获取共享内存shmget

image-20230224212406973

#include "head.h"

int main() {
	//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	key_t key;
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	printf("key = 0x%x\n", key);
	//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	int shmid;
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	printf("shmid = %d\n", shmid);
	return 0;
}

image-20230224221845280

3.绑定共享内存shmat

image-20230225230606913

#include "head.h"

int main() {
	//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	key_t key;
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	printf("key = 0x%x\n", key);
	//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	int shmid;
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	printf("shmid = %d\n", shmid);
	//3.将进程的动态内存空间和 共享内存空间关联
	void *shmemory = NULL;
	if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {
		perror("shmat");
		exit(1);
	}
	sleep(10);
	return 0;
}

image-20230225232517349

4.绑定分离shmdt

image-20230225232744715

#include "head.h"

int main() {
	//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	key_t key;
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	printf("key = 0x%x\n", key);
	//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	int shmid;
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	printf("shmid = %d\n", shmid);
	//3.将进程的动态内存空间和 共享内存空间关联
	void *shmemory = NULL;
	if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {
		perror("shmat");
		exit(1);
	}
	//4.将进程的动态内存空间和 共享内存空间关联解除
	int flag;
	if ((flag = shmdt(shmemory)) < 0) {
		perror("shmdt");
		exit(1);
	}
	return 0;
}

5.控制共享内存shmctl

image-20230226002223768

#include "head.h"

int main() {
	//1.申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	key_t key;
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	printf("key = 0x%x\n", key);
	//2.根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	int shmid;
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	printf("shmid = %d\n", shmid);
	//3.将进程的动态内存空间和 共享内存空间关联
	void *shmemory = NULL;
	if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {
		perror("shmat");
		exit(1);
	}
	//4.将进程的动态内存空间和 共享内存空间关联解除
	int flag;
	if ((flag = shmdt(shmemory)) < 0) {
		perror("shmdt");
		exit(1);
	}
	//5.shmctl删除共享内存空间
	if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {
		perror("shmctl");
		exit(1);
	}
	return 0;
}

三、亲缘进程间通信

1.共享内存写入与读取

#include "head.h"

//共享内存综合运用
int main() {
	key_t key;
	int shmid;
	pid_t pid;
	char *shmemory = NULL;
	//1.开辟一块共享内存空间
	//(1)申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	//(2)根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	//(3)将进程的动态内存空间和 共享内存空间关联
	if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {
		perror("shmat");
		exit(1);
	}
	//2.创建子进程 进行运算操作
	if ((pid = fork()) < 0) {
		perror("fork");
		exit(1);
	}
	if (pid) {//父进程写入
		while(1) {
			printf("i am the father : \n");
			scanf("%[^\n]s", shmemory);//向共享内存中写入
			getchar();//吞掉回车否则不停循环
			sleep(2);
		}
	} else {//子进程读出
		while (1) {
			sleep(1);
			if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);//如果共享内存空间中有数据才进行输出
			memset(shmemory, 0, 4096);//临时清空共享存储空间
		}
	}
	return 0;
}

image-20230228214143422

2.共享内存解绑与删除

#include "head.h"

//共享内存综合运用
int main() {
	key_t key;
	int shmid;
	pid_t pid;
	char *shmemory = NULL;
	//1.开辟一块共享内存空间
	//(1)申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	if ((key = ftok("1.ftok.c", 123)) < 0) {
		perror("ftok");
		exit(1);
	}
	//(2)根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {
		perror("shmget");
		exit(1);
	}
	//(3)将进程的动态内存空间和 共享内存空间关联
	if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {
		perror("shmat");
		exit(1);
	}
	//2.创建子进程 利用shmdt实现 一次读取一次读入操作
	if ((pid = fork()) < 0) {
		perror("fork");
		exit(1);
	}
	if (pid) {
		printf("i am the father : \n");
		scanf("%[^\n]s", shmemory);
		getchar();
	} else {
		sleep(5);
		if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);
		memset(shmemory, 0, 4096);
	}
	//3.删除开辟的共享内存空间
	//(1)将进程的动态内存空间和 共享内存空间关联解除
	int flag;
	if ((flag = shmdt(shmemory)) < 0) {
		perror("shmdt");
		exit(1);
	}
	//(2)shmctl删除共享内存空间(父进程执行)
	if (pid) {
		wait(NULL);
		if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {
			perror("shmctl");
			exit(1);
		}
	}
    sleep(5);
	return 0;
}

image-20230228215903113

3.共享内存综合

  • 利用共享内存实现多进程前n项数求和(利用共享内存实现)
#include "head.h"

struct data {
	int now;//中间结果
	int sum;//求和结果
};

void doSum(struct data *d, int max, int i) {
	while (1) {//计算的过程需要上锁
		if (d->now >= max) break;//判断 计算结果
		d->now++;
		d->sum += d->now;
		printf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);
	}
}

int main(int argc, char *argv[]) {
	//1.命令行解析 a.out -i -n n
	int opt;
	int ins = 1, max = 100;
	// struct data d;
	// d.now = 0;
	// d.sum = 0;
	// setnum(&d);
	while ((opt = getopt(argc, argv, "i:n:")) != -1) {
		switch (opt) {
		case 'i':
			ins = atoi(optarg);
			break;
		case 'n':
			max = atoi(optarg);
			break;
		default:
			fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);
			exit(1);
		}
	}
	//2.共享内存的创建于绑定
	key_t key;
	int shmid;
	struct data *shmemory = NULL;
	//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	if ((key = ftok("5.shm_sum.c", 123)) == -1) {
		perror("ftok");
		exit(1);
	}
	//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	if ((shmid = shmget(key, sizeof(struct data), IPC_CREAT | 0600)) < 0) {
		perror("shmget");
		exit(1);
	}
	//2.3将进程的动态内存空间和 共享内存空间关联
	if ((shmemory = (struct data *)shmat(shmid, NULL, 0)) == (struct data *)-1) {
		perror("shmat");
		exit(1);
	}
	shmemory->now = 0;
	shmemory->sum = 0;
	//3.创建ins个子进程对文件进行doSum操作
	int i;
	pid_t pid;
	for (i = 0; i < ins; ++i) {
		if ((pid = fork()) < 0) {
			perror("fork()");
			exit(1);
		}
		if (pid == 0) break;
	}
	if (pid == 0) {
		doSum(shmemory, max, i);
	} else {
		for (int k = 0; k < ins; ++k) wait(NULL);
		printf("%d\n", shmemory->sum);
	}
	return 0;
}

image-20230228223341746

image-20230228223606341

成功输出结果,前100项求和的结果为5050,但是当使用程序求前10000项和时,却会出现问题如图结果为50007661(错误结果)。

image-20230228223444201

出现问题的原因是:执行中的进程没有保障,进程之间发生竞争(同一时刻多个进程对内存进行读写操作,发生在多核处理器)

可以利用条件变量实现线程同步机制(进程同步),从而避免资源抢占竞争。

四、非亲缘进程间通信

共享内存实现多进程计算,

  1. 单核不考虑同步关系,可以正常实现
  2. 多核不考虑同步关系,无法正常实现
  3. 需要设置同步关系
  4. 利用条件变量实现进程同步

非亲缘进程之间的通信,

1.通过sleep同步

  • 使用共享内存实现两个非亲缘关系进程(1号进程、2号进程)进行通话
  • 1号进程只输出2号进程在共享内存中输入的数据
  • 2号进程只输出1号进程在共享内存中输入的数据
  • 同步(通过sleep实现同步)
#include "head.h"

struct SHM {
	int flag;//SHM能否读写
	int type;//第几个进程
	char mesg[50];//输入的信息
};

int main(int argc, char *argv[]) {
	//1.命令行解析 ./a.out -t 1|2 -m message
	int opt;
	int type;
	char mesg[50];
	struct SHM *temp;//用于临时存放准备写入共享内存的数据
	if (argc != 5) {
		fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);
		exit(1);
	}
	while ((opt = getopt(argc, argv, "t:m:")) != -1) {
		switch (opt) {
			case 't':
				type = atoi(optarg);
				break;
			case 'm':
				strcpy(mesg, optarg);
				break;
			default:
				fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);
				exit(1);
		}
	}
	/**
	 *存在问题
	 *为什么直接在switch中使用 temp->type = atoi(optarg); 会出现segmentfault呢?
	 *必须使用临时变量 int type; 来转接数据才不会报错? 
	*/
	temp->type = type;
	strcpy(temp->mesg, mesg);
	
	//2.共享内存的创建与绑定
	key_t key;
	int shmid;
	struct SHM *shmemory = NULL;
	//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	if ((key = ftok("1.shm_my.c", 123)) == -1) {
		perror("ftok");
		exit(1);
	}
	//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {
		if (errno == EEXIST) {//处理重复创建共享内存空间
			if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {
				perror("shmget1");
				exit(1);
			}
			printf("shmemory exist!");
		} else {
			perror("shmget2");
			exit(1);
		}
	}
	//2.3将进程的动态内存空间和 共享内存空间关联
	if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {
		perror("shmat");
		exit(1);
	}
	
	//3.实现非亲缘进程间通信
	shmemory->flag = 0;//初始状态为允许写入
	while (1) {
		if (!shmemory->flag) {
			printf("<Process%d> : i get shmemory\n", temp->type);
			sprintf(shmemory->mesg, "<Process%d> : <%s>", temp->type, temp->mesg);//向共享内存中写入内容
			shmemory->flag = 1;
			sleep(1);
		} else {
			printf("%s\n", shmemory->mesg);//从共享内存中读取 并输出内容
			shmemory->flag = 0;
		}
	}
	return 0;
}

image-20230301103041419

2.通过条件变量同步

思考:如何通过条件变量以及互斥锁,通过共享内存空间实现多进程同步

  • 一个进程1号进程,作为主要发送进程
  • 多个进程,输出1号进程发送的数据
  • 利用条件变量和互斥锁实现同步

image-20230301110138124

#include "head.h"

struct SHM {
	int type;//第几个进程
	char mesg[50];//输入的信息
	pthread_mutex_t mutex;//互斥锁
	pthread_cond_t cond;//条件变量
};

int main(int argc, char *argv[]) {
	//1.命令行解析 ./a.out -t 1|2
	int opt;
	int type;
	if (argc != 3) {
		fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);
		exit(1);
	}
	while ((opt = getopt(argc, argv, "t:")) != -1) {
		switch (opt) {
			case 't':
				type = atoi(optarg);
				break;
			default:
				fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);
				exit(1);
		}
	}
	
	//2.共享内存的创建与绑定
	key_t key;
	int shmid;
	struct SHM *shmemory = NULL;
	//2.1申请一块共享内存 将projectId与文件名字转换为 共享内存键值
	if ((key = ftok("2.shm_cond.c", 123)) == -1) {
		perror("ftok");
		exit(1);
	}
	//2.2根据共享内存对应的key值 和内存大小size 得到共享内存的标识符
	if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {
		if (errno == EEXIST) {//处理重复创建共享内存空间
			if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {
				perror("shmget1");
				exit(1);
			}
			printf("shmemory exist!\n");
		} else {
			perror("shmget2");
			exit(1);
		}
	}
	//2.3将进程的动态内存空间和 共享内存空间关联
	if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {
		perror("shmat");
		exit(1);
	}
	
	//3.实现非亲缘进程间通信
	if (type == 1) {//让1号进程初始化互斥锁和信号量 并设为共享
		pthread_mutexattr_t mutex;
		pthread_condattr_t cond;
		pthread_mutexattr_init(&mutex);
		pthread_condattr_init(&cond);
		pthread_mutexattr_setpshared(&mutex, 1);//设置为共享
		pthread_condattr_setpshared(&cond, 1);//设置为共享

		pthread_mutex_init(&shmemory->mutex, &mutex);//初始化锁
		pthread_cond_init(&shmemory->cond, &cond);//初始化条件
	}
	if (type == 1) {
		while (1) {
			printf("ok\n");
			scanf("%[^\n]s", shmemory->mesg); getchar();
			if (strlen(shmemory->mesg)) pthread_cond_signal(&shmemory->cond);//1号进程写入后通知其他进程
		}
	} else {
		while (1) {
			pthread_mutex_lock(&shmemory->mutex);//一旦有某个进程拿到了共享内存 则将共享内存上锁
			pthread_cond_wait(&shmemory->cond, &shmemory->mutex);//共享内存上锁后 等待1号进程写入完成的通知
			//if (strlen(shmemory->mesg)) 
			printf("<Process%d> : %s\n", type, shmemory->mesg);//将共享内存中写入的数据输出
			memset(shmemory->mesg, 0, strlen(shmemory->mesg));//清空共享内存
			pthread_mutex_unlock(&shmemory->mutex);
		}
	}
	return 0;
}

image-20230301171032340

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

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

相关文章

Android 进阶——Binder IPC之Native 服务的启动及代理对象的获取详解(六)

文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求二、Service 代理对象的获取1、获取Service Manager 代理对象BpServiceManager2、调用BpServiceManager#ge…

【算法数据结构体系篇class16】:图 拓扑排序

一、图1&#xff09;由点的集合和边的集合构成2&#xff09;虽然存在有向图和无向图的概念&#xff0c;但实际上都可以用有向图来表达3&#xff09;边上可能带有权值二、图结构的表达1&#xff09;邻接表法 类似哈希表, key就是当前节点。value就是对应有指向的邻接节点2&…

LeetCode——1590. 使数组和能被 P 整除

一、题目 给你一个正整数数组 nums&#xff0c;请你移除 最短 子数组&#xff08;可以为 空&#xff09;&#xff0c;使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度&#xff0c;如果无法满足题目要求&#xff0c;返回 -1…

PostgreSQL 数据库大小写规则

PostgreSQL 数据库对大小写的处理规则如下&#xff1a; 严格区分大小写默认把所有 SQL 语句都转换成小写再执行加双引号的 SQL 语句除外 如果想要成功执行名称中带有大写字母的对象&#xff0c;则需要把对象名称加上双引号。 验证如下&#xff1a; 想要创建数据库 IZone&…

Windows WSL配置ubuntu环境并登录

一、Windows WSL配置ubuntu环境1、管理员运行cmd&#xff0c;执行以下命令启用“适用于 Linux 的 Windows 子系统”dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart2、管理员运行cmd&#xff0c;执行以下命令启用“虚拟机功…

浅谈ChatGPT

ChatGPT概述 ChatGPT是一种自然语言处理模型&#xff0c;ChatGPT全称Chat Generative Pre-trained Transformer&#xff0c;由OpenAI开发。它使用了基于Transformer的神经网络架构&#xff0c;可以理解和生成自然语言文本。ChatGPT是当前最强大和最先进的预训练语言模型之一&a…

windows应用(vc++2022)MFC基础到实战(3)-基础(3)

目录框架调用代码MFC 对象之间的关系访问其他对象CWinApp&#xff1a;应用程序类initInstance 成员函数运行成员函数OnIdle 成员函数ExitInstance 成员函数CWinApp 和 MFC 应用程序向导特殊 CWinApp 服务Shell 注册文件管理器拖放CWinAppEx 类用于创建 OLE 应用程序的操作顺序用…

【算法题目】【Python】一文刷遍贪心算法题目

文章目录介绍分配饼干K 次取反后最大化的数组和柠檬水找零摆动序列单调递增的数字介绍 贪心算法是一种基于贪心思想的算法&#xff0c;它每次选择当前最优的解决方案&#xff0c;从而得到全局最优解。具体来说&#xff0c;贪心算法在每一步都做出局部最优选择&#xff0c;希望…

Flutter——Isolate主线机制

简述 在DartFlutter应用程序启动时&#xff0c;会启动一个主线程其实也就是Root Isolate,在Root Isolate内部运行一个EventLoop事件循环。所以所有的Dart代码都是运行在Isolate之中的&#xff0c;它就像是机器上的一个小空间&#xff0c;具有自己的私有内存块和一个运行事件循…

Linux下LED灯驱动模板详解

一、地址映射我们先了解MMU&#xff0c;全称是Memory Manage Unit。在老版本的Linux中要求处理器必须有MMU&#xff0c;但是现在Linux内核已经支持五MMU。MMU主要完成的功能如下&#xff1a;1、完成虚拟空间到物理空间的映射2、内存保护&#xff0c;设置存储器的访问权限&#…

【Linux学习笔记】mmap-共享内存进程通信 vs 有名信号量和无名信号量

mmap和信号量实现进程间通信相关mmap1. mmap 使用的注意事项2. mmap的两种映射3. mmap调用接口以及参数4. 使用存储映射区实现父子进程间通信&#xff08;有名&#xff09;父子进程通信的三种方式unlink5. 创建匿名存储映射区6. 通过存储映射区实现非血缘关系进程间的通信信号量…

SiteSucker for macOS + CRACK

SiteSucker for macOS CRACK SiteSucker是一个简单的macOS应用程序&#xff0c;允许您下载网站。它还可以将网站、网页、背景图片、视频和许多其他文件复制到Mac的硬盘上。 SiteSucker是一个Macintosh应用程序&#xff0c;可以自动下载Internet上的网页。它通过将网站的页面、…

遥感影像道路提取算法——SGCN

论文介绍 Split Depth-wise Separable Graph Convolution Network for Road Extraction in Complex Environment from High-resolution Remote Sensing Imagery&#xff08;TGRS&#xff09; 用于从高分辨率遥感图像&#xff08;TGRS&#xff09;中提取复杂环境中道路的分割深…

java对象的创建与内存分配机制

文章目录对象的创建与内存分配机制对象的创建类加载检查分配内存初始化零值设置对象头指向init方法其他&#xff1a;指针压缩对象内存分配对象在栈上分配对象在Eden区中分配大对象直接分配到老年代长期存活的对象进入老年代对象动态年龄判断老年代空间分配担保机制对象的内存回…

Spring的核心模块:Bean的生命周期(内含依赖循环+业务场景)。

Bean的生命周期前言为什么要学习Bean的生命周期前置知识Spring Post-processor&#xff08;后置处理器&#xff09;Aware接口简单介绍Bean的实例化过程为什么会有bean的实例化&#xff1f;过程Bean的初始化阶段为什么会有Bean的初始化&#xff1f;Bean的初始化目的是什么&#…

线性和非线性最小二乘问题的常见解法总结

线性和非线性最小二乘问题的各种解法 先看这篇博客&#xff0c;非常好&#xff1a;线性和非线性最小二乘问题的各种解法 1. 线性最小二乘问题有最优解 但是面对大型稀疏矩阵的时候使用迭代法效率更好。 迭代法 有Jacobi迭代法、 Seidel迭代法及Sor法 【数值分析】Jacobi、Se…

[ubuntu][GCC]gcc源码编译

1.下载gcc安装包 https://ftp.gnu.org/gnu/gcc/ 选择一个需要的gcc版本&#xff0c;下载。 2.下载依赖包 查看下载的gcc安装包中contrib文件夹下的download_prerequisites文件&#xff0c;查看需要的依赖包版本。 根据download_prerequisites中红框位置的信息&#xff0c;在下…

JSON.stringify()的5种使用场景

JSON.stringify() 方法将一个JavaScript对象或值转换为JSON字符串&#xff0c;如果指定了一个replacer函数&#xff0c;则可以选择性地替换值&#xff0c;或者指定的replacer是数组&#xff0c;则可选择性地仅包含数组指定的属性。 语法如下&#xff1a; JSON.stringify(value…

电子技术课程设计基于FPGA的音乐硬件演奏电路的设计与实现

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;乐曲电路 免费获取完整无水印论文报告&#xff08;包含电路图&#xff09; 文章目录一、设计任务要求二、总体框图三、选择器件四、功能模块五、总体设计电路图六、结束语一、设计任务要求 1、课程设计题目 设计一个乐曲演…

【Flutter从入门到入坑之三】Flutter 是如何工作的

【Flutter从入门到入坑之一】Flutter 介绍及安装使用 【Flutter从入门到入坑之二】Dart语言基础概述 【Flutter从入门到入坑之三】Flutter 是如何工作的 本文章主要以界面渲染过程为例&#xff0c;介绍一下 Flutter 是如何工作的。 页面中的各界面元素&#xff08;Widget&…