进程间通信2

3. system  V-IPC 

3.1 知识点

ipcs -a查看所有的ipc对象

在系统中他们都使用一种叫做 key 的键值来唯一标识,而且他们都是“持续性”资源——即他 们被创建之后,不会因为进程的退出而消失,而会持续地存在,除非调用特殊的函数或者命 令删除他们。

跟文件类型,进程每次“打开”一个 IPC 对象,就会获得一个表征这个对象的 ID,进而再使用这个 ID 来操作这个对象。IPC 对象的 key 是唯一的,但是 ID 是可变的。key 类似于文件的路径名,ID 类似于文件的描述符

系统中的多个进程,如果他们需要使用IPC 对象来通信,那么他们必须持有这个对象的 键值 key:

3.1.1 创建key

path:这是一个字符串,通常是指向一个存在的文件的路径。ftok() 将使用这个路径名来生成键。这个路径名应该是一个可访问的文件,因为它的存在与访问权限会影响键的生成。通常情况下,不同的路径名会生成不同的键。

proj:这是一个整数,通常取值在0到255之间。它用于在指定路径名的情况下生成唯一的键。如果不同的进程使用相同的路径名,可以通过不同的 proj 值生成不同的键。通常,每个IPC对象(消息队列、信号量、共享内存)都会有一个唯一的 proj 值。

这个函数需要注意的几点:

1,如果两个参数相同,那么产生的 key 值也相同。

2 ,第一个参数一般取进程所在的目录,因为在一个项目中需要通信的几个进程通常会 出现在同一个目录当中。

3 ,如果同一个目录中的进程需要超过 1 个 IPC 对象,可以通过第二个参数来标识。

4 ,系统中只有一套 key 标识,也就是说,不同类型的 IPC 对象也不能重复。 

3.1.2 查看和删除ipc

可以使用以下命令来查看或删除当前系统中的IPC 对象:

查看消息队列:ipcs -q

查看共享内存:ipcs -m

查看信号量:ipcs -s

查看所有的 IPC 对象:ipcs -a

删除指定的消息队列:ipcrm -q MSG_ID 或者 ipcrm -Q msg_key

删除指定的共享内存:ipcrm -m SHM_ID 或者 ipcrm -M shm_key

删除指定的信号量:ipcrm -s SEM_ID 或者 ipcrm -S sem_key

3.2  消息队列

3.2.1 创建消息队列,获取操作id

权限只有读和写,执行权限是无效的,例如 0777 跟 0666 是等价的。

删除消息队列

可以用

ipcrm -q 消息队列id

或者

ipcrm -Q 消息队列的key

3.2.2 发送和接收消息

使用这两个收、发消息函数需要注意以下几点:

1,发送消息时,消息必须被组织成以下形式:

struct msgbuf

{

long mtype;  // 消息的标识

char mtext[1];    // 消息的正文

};

也就是说:发送出去的消息必须以一个 long 型数据打头,作为该消息的标识,后 面的数据则没有要求。

2,消息的标识可以是任意长整型数值,但不能是 0L。

3,参数 msgsz 是消息中正文的大小,不包含消息的标识。

3.2.3 代码

ipc_msg_que_send.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>//消息队列的使用struct msgbuf
{long mtype;//消息的标识(整数)char mtext[128];//消息的正文
};int main()
{//创建keykey_t key = ftok("/",0);//创建消息队列,获取操作消息队列的idint msg_id = msgget(key,IPC_CREAT | 0777);if(msg_id == -1){perror("msg_id error");}struct msgbuf buf;buf.mtype = 1;while(1){memset(buf.mtext,0,sizeof(buf.mtext));//清零fgets(buf.mtext,sizeof(buf.mtext),stdin);//获取输入//发送msgsnd(msg_id,&buf,128,0);}return 0;
}
ipc_msg_que_receive.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>//消息队列的使用struct msgbuf
{long mtype;//消息的标识(整数)char mtext[128];//消息的正文
};int main()
{//创建keykey_t key = ftok("/",0);//创建消息队列,获取操作消息队列的idint msg_id = msgget(key,IPC_CREAT | 0777);if(msg_id == -1){perror("msg_id error");}struct msgbuf msg;while(1){memset(msg.mtext,0,sizeof(msg.mtext));//清零//接收msgrcv(msg_id,&msg,128,1,0);printf("receive msg: %s\n",msg.mtext);}return 0;
}

3.2.4 练习

1.设计一个消息队列程序,发送时,通过键盘来指定消息标识接收时,通过键盘来指定要接收的消息

ipc_que_test_w.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>//设计一个消息队列程序,发送时,通过键盘来指定消息标识接收时,通过键盘来指定要接收的消息
struct msgbuf{long mtype;//消息的标识(整数)char mtext[128];//消息的正文
};int main()
{//创建keykey_t key = ftok("/",4);//创建消息队列int msg_id = msgget(key,IPC_CREAT | 0777);if(msg_id==-1){perror("msg_id error");}struct msgbuf buf;int type;while(1){memset(buf.mtext,0,sizeof(buf.mtext));//键盘输入消息标识符printf("请输入发送消息标识符/(99退出):");scanf("%d",&type);if(type==99){break;}buf.mtype = type;getchar();//清空缓冲区//键盘接收消息正文printf("请输入消息正文:");fgets(buf.mtext,sizeof(buf.mtext),stdin);//发送msgsnd(msg_id,&buf,128,0);}return 0;
}
ipc_que_test_r.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>//设计一个消息队列程序,发送时,通过键盘来指定消息标识接收时,通过键盘来指定要接收的消息
struct msgbuf{long mtype;//消息的标识(整数)char mtext[128];//消息的正文
};int main()
{//创建keykey_t key = ftok("/",4);//创建消息队列int msg_id = msgget(key,IPC_CREAT | 0777);if(msg_id==-1){perror("msg_id error");}struct msgbuf buf;int type;while(1){memset(buf.mtext,0,sizeof(buf.mtext));//键盘输入消息标识符printf("请输入接收消息标识符/(99退出):");scanf("%d",&type);if(type==99){break;}buf.mtype = type;printf("\n");//发送int ret = msgrcv(msg_id,&buf,128,type,0);printf("接收到标识符尾%d的消息为: %s\n",type,buf.mtext);}return 0;
}

3.3 共享内存

3.3.1 使用步骤

使用共享内存的一般步骤是:

1,获取共享内存对象的 ID

2,将共享内存映射至本进程虚拟内存空间的某个区域

3,当不再使用时,解除映射关系

4,当没有进程再需要这块共享内存时,删除它。

3.3.2 获取共享内存的 ID

共享内存的大小必须是偶数

3.3.3 共享内存映射

3.3.4 代码

ipc_share_w.c
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>//共享内存
int main()
{//创建key  和  获取共享内存idint share_id = shmget(ftok("/",1),1024,IPC_CREAT | 0777);//对共享内存进行映射  将这个共享内存映射至本进程的虚拟空间char* p = shmat(share_id,NULL,0);//p就是共享内存的首地址fgets(p,1024,stdin);//获取键盘输入shmdt(p);//解除映射return 0;
}
ipc_share_r.c
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>//共享内存
int main()
{//创建key  和  获取共享内存idint share_id = shmget(ftok("/",1),1024,IPC_CREAT | 0777);//对共享内存进行映射  将这个共享内存映射至本进程的虚拟空间char* p = shmat(share_id,NULL,0);//p就是共享内存的首地址printf("%s\n",p);//打印shmdt(p);//解除映射return 0;
}

3.4 信号量

一些基本概念如下:

1,多个进程或线程有可能同时访问的资源 (变量、链表、文件等等) 称为共享资源, 也叫临界资源 (critical resources) 。

2,访问这些资源的代码称为临界代码,这些代码区域称为临界区 (critical zone) 。

3,程序进入临界区之前必须要对资源进行申请,这个动作被称为 P 操作,这就像你要 把车开进停车场之前,先要向保安申请一张停车卡一样,P 操作就是申请资源,如果申请成 功,资源数将会减少。如果申请失败,要不在门口等,要不走人。

4,程序离开临界区之后必须要释放相应的资源,这个动作被称为 V 操作,这就像你把 车开出停车场之后,要将停车卡归还给保安一样,V 操作就是释放资源,释放资源就是让资 源数增加。

system-V 的信号量并不是单个的值,而是一组 (事实上是一个数 组) 信号量元素构成的

信号量跟前面的 MSG 和 SHM 有极大的不同,SEM 不是用来传输数据的,而 是作为“旗语”,用来协调各进程或者线程工作的。

信号量的 P、V 操作最核心的特征是:他们是原子性的,也就是说对信号量元素的值的 增加和减少,系统保证在 CPU 的电气特性级别上不可分割,这跟整型数据的加减法有本质 的区别。

3.4.1 创建信号量获取操作id

创建信号量时,还受到以下系统信息的影响:

1,SEMMNI:系统中信号量的总数最大值。

2,SEMMSL:每个信号量中信号量元素的个数最大值。

3,SEMMNS:系统中所有信号量中的信号量元素的总数最大值。

Linux 中,以上信息在/proc/sys/kernel/sem 中可查看。

3.4.2 获取或者设置信号量的相关属性

使用以上函数接口,需要注意以下几点:

1,这是一个变参函数,根据cmd 的不同,可能需要第四个参数,第四个参数是一个如 下所示的联合体,用户必须自己定义:

union semun

{

int   val;        /* 当 cmd 为 SETVAL 时使用 */

struct semid_ds *buf;       /* 当 cmd 为 IPC_STAT 或 IPC_SET 时使用 */

unsigned short   *array;   /* 当 cmd 为 GETALL 或 SETALL 时使用 */

struct seminfo   *__buf;   /* 当 cmd 为 IPC_INFO 时使用 */

};

3.4.3 对信号量进行 P/V 操作,或者等零操作

使用以上函数接口需要注意以下几点:

1,信号量操作结构体的定义如下:

struct sembuf

{

unsigned short short  sem_num;    /* 信号量元素序号 (数组下标)  */

short   sem_op;       /* 操作参数 */

short sem_flg;                  /* 操作选项 */

};

请注意:信号量元素的序号从 0 开始,实际上就是数组下标。

1. 当 sem_op 大于 0 时:进行 V 操作,即信号量元素的值 (semval) 将会被加上 sem_op 的值。

2. 当 sem_op 等于 0 时:进行等零操作

3. 当 sem_op 小于 0 时:进行 P 操作,即信号量元素的值 (semval) 将会被减去 sem_op 的绝对值。

重点

一个信号量(Semaphore)通常对应一个 struct sembuf 数组,但这个 struct sembuf 数组可以包含多个操作,而不仅限于一个操作。让我更详细地解释:

一个信号量对应一个 struct sembuf 数组:每个信号量在信号量集合中都有一个唯一的标识符,你可以使用这个标识符来指定要操作的信号量。通常情况下,你会创建一个 struct sembuf 数组,其中的每个元素描述了对某个特定信号量的操作。

一个 struct sembuf 数组可以包含多个操作:在 struct sembuf 数组中,你可以定义多个操作,这些操作都是针对同一个信号量的。每个 struct sembuf 结构体包括三主要字段:sem_num(信号量集合中的索引,用于指定操作的目标信号量)、sem_op(要执行的操作,通常是 -1 表示 P 操作或 1 表示 V 操作),以及 sem_flg(标志位,通常设置为 0)。

所以,你可以创建一个 struct sembuf 数组,其中的每个元素描述了对同一个信号量的不同操作。这种方式允许你在一个数组中组织多个操作,以便在一次函数调用中执行多个操作,这些操作都是基于同一个信号量的。

总结,一个信号量对应一个 struct sembuf 数组,而这个数组可以包含多个操作,用于对该信号量执行不同的操作。这是一种有效的方式来管理并发访问共享资源或进行同步操作。

3.4.5 代码

sys_sem_w.c
#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>#define DATA 0
#define SPACE 1//共享内存的结合信号量,循环写入0-9
union semun
{int                          val;       /* 当 cmd 为 SETVAL 时使用 */struct semid_ds *buf;     /* 当 cmd 为 IPC_STAT 或 IPC_SET 时使用 */unsigned short         *array;  /* 当 cmd 为 GETALL 或 SETALL 时使用 */struct seminfo          *__buf; /* 当 cmd 为 IPC_INFO 时使用 */
};void sem_init(int id, int semnum, int val)
{union semun a;a.val = val;semctl(id, semnum,SETVAL, a);
}void sem_p(int id,int semnum)//资源-1
{struct sembuf sops[1];sops[0].sem_num = semnum;sops[0].sem_op = -1;sops[0].sem_flg = 0;semop(id, sops, 1);
}void sem_v(int id, int semnum)//资源+1
{struct sembuf sops[1];sops[0].sem_num = semnum;sops[0].sem_op = 1;sops[0].sem_flg = 0;semop(id, sops, 1);
}int main()
{//创建共享内存的IPC对象int shmid = shmget(ftok("/",2), 2,IPC_CREAT | 0666);//共享内存的大小必须是偶数,实际上在本代码中只需要1个char *p = shmat(shmid, NULL, 0);//映射//创建信号量的IPC对象int sem_id = semget(ftok("/",3),2,IPC_CREAT | 0666);//数据当0//数据初始化为0个sem_init(sem_id, DATA, 0);//空间当1//空间初始化为1个sem_init(sem_id, SPACE, 1);char *msg = "0123456789";int i = 0;while(1){//1个空间//0个数据//写入数据sem_p(sem_id,SPACE);//p -1 s 0memcpy(p, msg+i, 1);//0,1,2,3,4,5,6,7,8,9sem_v(sem_id,DATA);//v +1   d 1i = (i+1)%10;//10%10=0}
}
 sys_sem_r.c
#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
//共享内存的结合信号量,循环写入0-9
//首先搞清楚一个概念 信号量集合中可以有多个信号量,一个信号量对应一个struct sembuf sops[]结构体数组
//, 一个信号量可以有多个资源也就是说一个struct sembuf sops[]结构体数组可以有多个元素//这里两个宏定义 的0  1 可以理解为信号量的下标(因为有的情况会有很多个信号量
//我们的例子中只有两个信号量,如果有多个的话 就是 0  1 2 3 4.....这样排下去)
#define DATA 0
#define SPACE 1//获取或设置信号量的相关属性涉及到的结构体
union semun
{int        val;       /* 当 cmd 为 SETVAL 时使用 */struct semid_ds *buf;     /* 当 cmd 为 IPC_STAT 或 IPC_SET 时使用 */unsigned short         *array;  /* 当 cmd 为 GETALL 或 SETALL 时使用 */struct seminfo          *__buf; /* 当 cmd 为 IPC_INFO 时使用 */
};//信号量初始化
void sem_init(int id, int semnum, int val)
{union semun a;//联合体a.val = val;//获取或设置信号量的相关属性//第二个参数是指定哪个信号量//这是一个变参函数 第三个参数SETVAL(设置该信号量元素的值) 会影响第四个参数应该传递啥(参数是个联合体)//这里带入解释一下我们假如传来的的是我们定义的SPACE信号量,val参数为1//参数semnum是SPACE   所以semctl函数的意思是,给SPACE信号量 设置该信号量元素的值为 a联合体//因为我们第三个参数使用的是SETVAL 所以a联合体中主要用到属性val被赋值为该信号量元素的值为1semctl(id, semnum,SETVAL, a);
}//p操作
void sem_p(int id,int semnum)//资源-1
{//这个结构体数组可以有多个元素,代表同一个信号量可以携带多个资源并在一个函数内对多个资源操作//这里我们的一个信号量只设置了一个资源,所以结构体数组的大小为1,千万别被迷惑了struct sembuf sops[1];sops[0].sem_num = semnum; //semnum指定信号量sops[0].sem_op = -1;sops[0].sem_flg = 0;//对信号量进行pv操作的函数,这个函数的第二参数需要一个struct sembuf类型的结构体数组//所以我们上面才会定义一个结构体数组//第三个参数 就是你的结构体数组中有几个元素semop(id, sops, 1);
}//v操作
void sem_v(int id, int semnum)//资源+1
{struct sembuf sops[1];sops[0].sem_num = semnum;sops[0].sem_op = 1;sops[0].sem_flg = 0;semop(id, sops, 1);
}int main()
{//创建共享内存的IPC对象,获取操作idint shmid = shmget(ftok("/",2), 2,IPC_CREAT | 0666);//共享内存的大小必须是偶数,实际上在本代码中只需要1个//将共享内存 映射 到虚拟内存char *p = shmat(shmid, NULL, 0);//创建信号量的IPC对象 ,,2,代表这里我们创建2个信号量int sem_id = semget(ftok("/",3),2,IPC_CREAT | 0666);//初始化信号量//数据信号量 的下标为0//数据初始化为0个sem_init(sem_id, DATA, 0);//这里的DATA代表它在信号量集合中的下标(就是我们上面的宏定义),0代表这个信号量的大小//空间信号量我们规定下标为1//空间初始化为1个sem_init(sem_id, SPACE, 1);char *msg = "0123456789";int i = 0;while(1){//1个空间//0个数据//写入数据//p操作sem_p(sem_id,DATA);//p -1 s 0fprintf(stderr,p);//v操作sem_v(sem_id,SPACE);//v +1   d 1i = (i+1)%10;//10%10=0}
}

编译运行

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

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

相关文章

Linux:docker的数据管理(6)

数据管理操作*方便查看容器内产生的数据 *多容器间实现数据共享 两种管理方式数据卷 数据卷容器 1.数据卷 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中&#xff0c;可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数…

1+x网络系统建设与运维(中级)-练习题

一.给设备重命名 同理可得&#xff0c;所有交换机和路由器都用一下命令配置 <Huawei>sys [Huawei]sysn LSW1 二.配置VLAN LSW1&#xff1a; [LSW1]vlan batch 10 20 [LSW1]int e0/0/1 [LSW1-Ethernet0/0/1]port link-type access [LSW1-Ethernet0/0/1]port default vlan…

微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践(一)

微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践 Power Pages 网页搭建 微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践1、Power Pages 介绍2、开始创建一个站点3、选择一个合适的模板4、编辑我们的模板5、面向专业开发人员的高级开发功能6、预览…

python 实现链表

链表基础知识 链表是在物理内存中不连续&#xff0c;数据通过链表中的指针来链接到下一个元素。 链表由一系列节点组成&#xff0c;节点在运行时动态生成&#xff0c;节点一般包括两个部分&#xff1a;存储数据的数据域&#xff0c;存储下一个节点的指针域 链表的常用操作&a…

Mysql数据库多表数据查询问题

1、背景 线上某个业务数据分表存储在10个子表中&#xff0c;现在需要快速按照条件&#xff08;比如时间范围&#xff09;筛选出所有的数据&#xff0c;主要是想做一个可视化的数据查询工具&#xff0c;给产研团队使用。 2、实践 注意&#xff1a;不要在线上真实数据库操作&am…

zookeeper集群+kaafka集群

kafka3.0之前依赖于zookeeper zookeeper开源&#xff0c;分布式的架构&#xff0c;提供协调服务&#xff08;Apache项目&#xff09; 基于观察者模式涉及的分布式服务管理架构 存储和管理数据&#xff0c;分布式节点上的服务接受观察者的注册&#xff0c;一旦分布式节点上的…

【网络安全技术】消息认证技术

一、哈希函数 1.安全性质 1&#xff09;抗第一原像攻击&#xff08;Preimage Resistance&#xff09; 给定哈希后的值&#xff0c;很难找到哈希前的原消息。这很好理解&#xff0c;需要哈希函数具有单向性。 一个简单的例子就是密码存储系统&#xff0c;用户登录服务器需要…

使用dirmap命令行时报错,提示缺少gevent模块

记得以前是可以的&#xff0c;可能是时间长了重装了系统&#xff0c;引起的。 修复方法。升级pip&#xff0c;然后重新下载安装gevent模块。 具体&#xff1a; 使用下面命令解决下载慢的问题。 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple …

python中,or、not的用法

or的用法 在python中,or运算符是一个逻辑运算符&#xff0c;用于在多个条件中选择至少一个为真&#xff08;True&#xff09;的情况。 如果条件中的任意一个为真&#xff0c;整个表达式的结果就为真 如&#xff1a; 示例1: 检查两个数字中至少有一个正数 示例2: x True y …

使用系统ProgressBar实现三色进度条

使用系统ProgressBar实现如图三色进度条&#xff1a; //布局中<ProgressBarandroid:layout_width"0dp"android:layout_height"8dp"android:layout_marginLeft"16dp"app:layout_constraintBottom_toBottomOf"id/photo"app:layout_c…

Linux 权限管理

1 Linux 安全模型 AAA认证资源分派&#xff1a; 当用户登录时&#xff0c;系统会自动分配令牌 token&#xff0c;包括用户标识和组成员等等信息 1.1 用户 Linux 中每个用户是通过 User ID&#xff08;UID&#xff09;来唯一标识的。 1.2 用户组 Linux 中可以将一个或者多个…

OOM了?物理内存不够了?试试这个方法来提升内存容量,不花钱的

通过增加虚拟内存来提高内存使用 本文解决的实际问题&#xff1a; 当我们物理内存小的时候&#xff0c;会出现OOM&#xff0c;然后服务自动死掉的情况。因为物理内存大小是固定的&#xff0c;有没有其他好的办法来解决呢&#xff1f;这里我们可以适当调整Linux的虚拟内存来协作…

spring cloud gateway源码分析,一个请求进来的默认处理流程

1.前言 spring cloud gateway的基本组成和作用就不细赘述&#xff0c;此篇适合对此有一定了解的人阅读。 spring cloud gateway版本: Hoxton.SR1 spring cloud gateway的配置使用yml配置&#xff1a; server:port: 9527y#根据微服务名称进行动态路由的配置 spring:applicati…

【Amazon】通过代理连接的方式导入 AWS EKS集群至KubeSphere主容器平台

文章目录 一、设置主集群方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 二、在主集群中设置代理服务地址方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 三、登录控制台验证四、准备成员集群方式一&#xff1a;使用 Web 控制台…

linux上编写进度条

目录 一、预备的两个小知识1、缓冲区2、回车与换行 二、倒计时程序三、编写入门的进度条四、编写一个正式的五、模拟实现和下载速度相关的进度条 一、预备的两个小知识 1、缓冲区 首先认识一下缓冲区&#xff1a;先写一个.c文件如下&#xff1a; 我们执行一下这个程序时&…

如何在vs2019及以后版本(如vs2022)上添加 添加ActiveX控件中的MFC类

有时候我们在MFC项目开发过程中&#xff0c;需要用到一些微软已经提供的功能&#xff0c;如VC使用EXCEL功能&#xff0c;这时候我们就能直接通过VS2019到如EXCEL.EXE方式&#xff0c;生成对应的OLE头文件&#xff0c;然后直接使用功能&#xff0c;那么&#xff0c;我们上篇文章…

索尼PMW580视频帧EC碎片重组开启方法

索尼PMW580视频帧EC碎片重组开启方法 索尼PMW-580摄像机生成的MXF文件存在严重的碎片化&#xff0c;目前CHS零壹视频恢复程序MXF版、专业版、高级版已经支持重组结构体正常的碎片&#xff0c;同时也支持对于结构体破坏或者覆盖后仅存在音视频帧EC数据的重组&#xff0c;需要注…

次世代建模纹理贴图怎么做?

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1、什么是次时代建模&#xff1f; "次世代建模"是一个术语&#xff0c;通常用来描述…

边缘数据中心和5G的融合彻底改变数据传输和物联网

伴随着数字化时代的飞速发展&#xff0c;边缘数据中心和5G技术的联袂崛起&#xff0c;正深刻塑造着人们对数据的创造、传输和处理方式。据Gartner公司的预测&#xff0c;到2025年&#xff0c;企业数据的三分之二将在边缘计算设施中涌现&#xff0c;而非传统的集中式数据中心。这…

抑郁症中西医治疗对比?

抑郁症是一种常见的心理障碍&#xff0c;治疗方法包括中医和西医两种。下面就抑郁症中西医治疗进行对比&#xff1a; 治疗方法&#xff1a;中医治疗抑郁症强调整体观念和辨证论治&#xff0c;通过调理身体各部分的功能&#xff0c;达到治疗抑郁症的目的。中医治疗抑郁症多采用天…