《Linux C编程实战》笔记:消息队列

消息队列是一个存放在内核中的消息链表,每个消息队列由消息队列标识符标识。与管道不同的是消息队列存放在内核中,只有在内核重启(即操作系统重启)或显示地删除一个消息队列时,该消息队列才会被真正的删除。

操作消息队列时,需要用到一些数据结构,熟悉这些数据结构是掌握消息队列的关键。下面介绍几个重要的数据结构

消息缓冲结构

向消息队列发送消息时,必须组成合理的数据结构。Linux系统定义了一个模板数据结构msgbuf

#include<linux/msg.h>
struct msgbuf {long mtype;          /* type of message */char mtext[1];                  /* message text */
};

结构体中的mtype字段代表消息类型。给消息指定类型,可以使得消息在一个队列中重复使用。mtext字段指消息内容。

mtext最然定义为char类型,并不代表消息只能是一个字符,消息内容可以为任意类型,由用户根据需要定义,如下面就是用户定义的一个消息结构

struct myMsgbuf{long mtype;struct student std;
}

消息队列中的消息的大小是受限制的,由<linux/msg.h>中的宏MSGMAX给出消息的最大长度,在实际应用中要注意这个限制。

msqid_ds内核数据结构

Linux内核中,每个消息队列都维护一个结构体msqid_qs,此结构体保存着消息队列当前的状态信息。该结构体定义在头文件linux/msg.h中,具体如下

struct msqid_ds {struct ipc_perm msg_perm;struct msg *msg_first;		/* first message on queue,unused  */struct msg *msg_last;		/* last message in queue,unused */__kernel_old_time_t msg_stime;	/* last msgsnd time */__kernel_old_time_t msg_rtime;	/* last msgrcv time */__kernel_old_time_t msg_ctime;	/* last change time */unsigned long  msg_lcbytes;	/* Reuse junk fields for 32 bit */unsigned long  msg_lqbytes;	/* ditto */unsigned short msg_cbytes;	/* current number of bytes on queue */unsigned short msg_qnum;	/* number of messages in queue */unsigned short msg_qbytes;	/* max number of bytes on queue */__kernel_ipc_pid_t msg_lspid;	/* pid of last msgsnd */__kernel_ipc_pid_t msg_lrpid;	/* last receive pid */
};
  1. msg_perm:用于存储IPC对象的权限信息以及队列的用户ID,组ID等信息。
  2. msg_first:队列中的第一个消息的指针。
  3. msg_last:队列中的最后一个消息的指针。
  4. msg_stime:上次发送消息的时间。
  5. msg_rtime:上次接收消息的时间。
  6. msg_ctime:上次修改消息队列的时间。
  7. msg_lcbytes:用于32位系统的字段,未使用。
  8. msg_lqbytes:用于32位系统的字段,未使用。
  9. msg_cbytes:当前队列中消息的总字节数。
  10. msg_qnum:队列中当前存在的消息数量。
  11. msg_qbytes:队列中允许的最大字节数。
  12. msg_lspid:最后一次发送消息的进程ID。
  13. msg_lrpid:最后一次接收消息的进程ID。

ipc_perm内核数据结构

结构体ipc_perm保存着消息队列的一些重要信息,比如消息队列关联的键值,消息队列的用户ID,组ID等,它定义在头文件linux/ipc.h中

struct ipc_perm
{__kernel_key_t	key;__kernel_uid_t	uid;__kernel_gid_t	gid;__kernel_uid_t	cuid;__kernel_gid_t	cgid;__kernel_mode_t	mode; unsigned short	seq;
};
  1. key:创建消息队列用到的键值key。
  2. uid:消息队列的用户ID(User ID)。
  3. gid:消息队列的组ID(Group ID)。
  4. cuid:创建消息队列的用户ID(User ID)。
  5. cgid:创建消息队列的组ID(Group ID)。
  6. mode:权限模式(Permission Mode),包括读、写、执行权限等。
  7. seq:序列号,用于确保唯一性和顺序性。

消息队列的创建与读写

创建消息队列

消息队列是随着内核的存在而存在的,每个消息队列在系统范围内对应唯一的键值。要获得一个消息队列的描述符,只需要提供该消息队列的键值即可,该键值通常通过ftok函数返回。该函数定义在头文件sys/ipc.h中

#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

ftok 函数通过将给定的文件路径名与给定的项目ID进行哈希运算生成一个唯一的键值。失败返回-1.

示例代码1

演示ftok的使用

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
int main(int argc,char **argv,char **environ){for(int i=1;i<=5;i++)printf("key[%d] = %u \n",i,ftok(".",i));return 0;
}

根据路径名和proj_id就会得到一个键值。

注意:参数pathname在系统中一定要存在且进程有权访问,参数proj_id的取值范围为1-255

ftok返回的键值可以提供给函数msgget。msgget根据这个键值创建一个新的消息队列或者访问一个已经存在的消息队列。msgget定义在头文件sys/msg.h中。

int msgget(key_t key, int msgflg);

该函数接受两个参数:

  1. key:消息队列的键值,通常使用 ftok 函数生成。它用于标识消息队列。

  2. msgflg:用于指定消息队列的创建和访问权限的标志。通常情况下,它可以是以下几个值的按位或组合:

    • IPC_CREAT:如果消息队列不存在,则创建一个新的消息队列。
    • IPC_EXCL:与 IPC_CREAT 一起使用时,如果消息队列已经存在,则返回错误。
    • 权限掩码:用于设置消息队列的访问权限,例如 0666

msgget 函数返回一个标识符,它是消息队列的唯一标识符。如果成功,返回值是一个非负整数;如果失败,返回值为 -1,并设置 errno 来指示错误的原因。

写消息队列

函数msgsnd用于向消息队列发送数据。该函数定义在头文件sys/msg.h中

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

该函数接受四个参数:

  1. msqid:消息队列的标识符,通常由 msgget 函数返回。

  2. msgp:指向消息数据的指针,通常是一个用户定义的结构体指针,用于存储要发送的数据。

  3. msgsz:消息的大小,以字节为单位。该值应该是 msgp 指向的数据结构的大小。

  4. msgflg:用于指定消息发送的行为标志,可以是以下之一或它们的按位或组合:

    • IPC_NOWAIT:如果消息队列已满,则立即返回,而不是等待空闲空间。
    • 0:默认行为,如果消息队列已满,则进程将被阻塞,直到有足够的空间将消息发送到队列中。

msgsnd 函数返回一个整数值,如果成功,返回值为 0;如果失败,返回值为 -1,并设置 errno 来指示错误的原因。

使用 msgsnd 函数时,需要确保指定的消息队列标识符有效,并且消息队列具有足够的空间来容纳要发送的消息。

示例程序2

演示往消息队列发消息

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
int main(int argc,char **argv,char **environ){//用户自定义消息缓存struct mymsgbuf{long msgtype;char ctrlstring[BUF_SIZE];}msgbuffer;int qid;int msglen;key_t msgkey;//获取键值if((msgkey=ftok(PATH_NAME,PROJ_ID))==-1){perror("ftok error!\n");exit(1);}//创建消息队列if((qid=msgget(msgkey,IPC_CREAT|0660))==-1){perror("msgget error!\n");exit(1);}//填充消息结构,发送到消息队列msgbuffer.msgtype=3;strcpy(msgbuffer.ctrlstring,"hello,message queue");msglen=sizeof(struct mymsgbuf)-4;if(msgsnd(qid,&msgbuffer,msglen,0)==-1){perror("msgget error!\n");exit(1);}exit(0);
}

ipcs 命令是用于列出当前系统上的 System V IPC(Inter-Process Communication)资源的信息,包括消息队列、信号量和共享内存。

从结果看,系统内部生成了一个消息队列,其中含有一条消息。

读消息队列

消息队列中放入数据后,其他进程就可以读取其中的信息了。读取消息队列的函数是msgrcv,该函数定义在头文件sys/msg.h中

#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
  1. msqid:消息队列的标识符,用于指定从哪个消息队列接收消息。
  2. msgp:一个指向消息缓冲区的指针,用于存储接收到的消息。
  3. msgsz:消息缓冲区的大小,即 msgp 指向的缓冲区的大小。
  4. msgtyp:指定要接收的消息类型。如果 msgtyp 为正数,则函数将接收第一个消息类型为 msgtyp 的消息。如果 msgtyp 为 0,则接收队列中的第一个消息,无论其类型是什么。如果 msgtyp 为负数,则接收队列中类型值最小且小于等于 msgtyp 绝对值的消息。
  5. msgflg:附加标志,用于控制函数的行为。可以使用 IPC_NOWAIT(如果没有可用消息,则立即返回)和/或 MSG_NOERROR(如果消息大于 msgsz,则截断消息)的组合。
  6. 如果函数成功接收到消息,则返回接收到的消息的字节数量。
  7. 如果函数调用失败,则返回 -1,并设置 errno 来指示错误的类型。

如果不设置IPC_NOWAIT的话,msgrcv也会阻塞进程

示例程序3

下面的例子就来读取之前发送的消息

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
int main(int argc,char **argv,char **environ){struct mymsgbuf{long msgtype;char ctrlstring[BUF_SIZE];}msgbuffer;int qid;int msglen;key_t msgkey;if((msgkey=ftok(PATH_NAME,PROJ_ID))==-1){perror("ftok error!\n");exit(1);}if((qid=msgget(msgkey,IPC_CREAT|0660))==-1){perror("msgget error!\n");exit(1);}//前面的都一样msglen=sizeof(struct mymsgbuf)-4;//第四个参数为什么是3呢,因为我们发的时候设置的就是3if(msgrcv(qid,&msgbuffer,msglen,3,0)==-1){perror("msgrcv error!\n");exit(1);}printf("Get message %s \n",msgbuffer.ctrlstring);exit(0);
}

因为给 ftok提供的参数是一样的,所以能得到对应的消息队列。因为我们已经创建了该消息队列,所以msgget就只是得到qid。

获取和设置消息队列的属性

上面介绍到了消息队列的属性保存在数据结构msqid_ds中,用户可以通过函数msgctl获取或设置消息队列的属性。msgctl定义在头文件sys/msg.h中

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • msqid 是消息队列的标识符,由msgget函数返回。
  • cmd 是命令,指定了你想执行的操作。常见的命令包括:
    • IPC_STAT:获取消息队列的当前状态。
    • IPC_SET:设置消息队列的属性。
    • IPC_RMID:删除消息队列。
  • buf 是一个指向msqid_ds结构的指针,用于存储或传递消息队列的状态信息。

示例程序4

演示如何获取和设置消息队列的属性

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<string.h>
#include<time.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
void getmsgattr(int msgid,struct msqid_ds msg_info);
int main(void){//自定义的消息缓冲区struct mymsgbuf{long msgtype;char ctrlstring[BUF_SIZE];}msgbuffer;int qid;int msglen;key_t msgkey;struct msqid_ds msg_attr;//获取键值if((msgkey=ftok(PATH_NAME,PROJ_ID))==-1){perror("ftok error!\n");exit(1);}//获取下奥西队列的标识符if((qid=msgget(msgkey,IPC_CREAT|0666))==-1){perror("msgget error!\n");exit(1);}getmsgattr(qid,msg_attr);//输出属性//发送一条消息到消息队列msgbuffer.msgtype=2;strcpy(msgbuffer.ctrlstring,"Aother message");msglen=sizeof(struct mymsgbuf)-4;if(msgsnd(qid,&msgbuffer,msglen,0)==-1){perror("msgget error!\n");exit(1);}getmsgattr(qid,msg_attr);//再次查看消息队列的属性//这次手动设置消息队列的属性msg_attr.msg_perm.uid=3;msg_attr.msg_perm.gid=2;if(msgctl(qid,IPC_SET,&msg_attr)==-1){//用msgctl函数修改perror("msg set error!\n");exit(1);}getmsgattr(qid,msg_attr);//输出修改后的属性//删除消息队列if(msgctl(qid,IPC_RMID,NULL)==-1){perror("delete msg error!\n");exit(1);}getmsgattr(qid,msg_attr);//删除后再观察属性exit(0);
}
void getmsgattr(int msgid,struct msqid_ds msg_info){if(msgctl(msgid,IPC_STAT,&msg_info)==-1){//通过msgctl获取消息队列的属性perror("msgctl error!\n");return;}//输出的内容参照前文对struct msqid_ds结构体的介绍printf("****information of message queue%d****\n",msgid);printf("last msgsnd to msg time is %s\n",ctime(&(msg_info.msg_stime)));printf("last msgrcv time from msg is %s\n",ctime(&(msg_info.msg_rtime)));printf("last change msg time is %s\n",ctime(&(msg_info.msg_ctime)));printf("current number of bytes on queue is %d\n",msg_info.__msg_cbytes);printf("number of messages in queue is %d\n",msg_info.msg_qnum);printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);printf("msg uid is %d\n",msg_info.msg_perm.uid);printf("msg gid is %d",msg_info.msg_perm.gid);printf("****infromation end!****\n");
}

执行结果的片段,因为太长截不下。

getmsgattr函数好像不需要第二个参数啊,直接在函数内部声明一个临时的就行,反正都是从消息队列里重新获取的。不知道书上为什么这么写。

示例程序5

上一节使用了有名管道实现了服务器和客户进程的通信,这回使用消息队列来完成。

server端:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/stat.h>
#include<sys/msg.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
#define SERVER_MSG 1
#define CLIENT_MSG 2    
int main(int argc,char **argv,char **environ){struct mymsgbuf{long msgtype;char ctrlstring[BUF_SIZE];}msgbuffer;int qid;int msglen;key_t msgkey;if((msgkey=ftok(PATH_NAME,PROJ_ID))==-1){perror("ftok error!\n");exit(1);}if((qid=msgget(msgkey,IPC_CREAT|0660))==-1){perror("msgget error!\n");exit(1);}//前面基本都一样,就是获取键值,获取消息队列的qidwhile(1){printf("server: ");fgets(msgbuffer.ctrlstring,BUF_SIZE,stdin);//从标准输入读if(strncmp("exit",msgbuffer.ctrlstring,4)==0){//如果是exit则删除消息队列退出msgctl(qid,IPC_RMID,NULL);break;}msgbuffer.ctrlstring[strlen(msgbuffer.ctrlstring)-1]='\0';msgbuffer.msgtype=SERVER_MSG;//标记是来自服务器端的信息if(msgsnd(qid,&msgbuffer,strlen(msgbuffer.ctrlstring)+1,0)==-1){//+1是因为还有\0perror("Server msgsnd error!\n");exit(1);}if(msgrcv(qid,&msgbuffer,BUF_SIZE,CLIENT_MSG,0)==-1){//接收来自客户端的信息perror("Server msgrcv error!\n");exit(1);}printf("Clinet:%s\n",msgbuffer.ctrlstring);}exit(0);
}

这里要解释一下msgbuffer.ctrlstring[strlen(msgbuffer.ctrlstring)-1]='\0';这一句代码

fgets会保存输入时的换行符,也就是说整个字符串是包括一个\n的,当然最后也包括\0,但是我们发送的信息不需要这个换行符,所以这句代码的意思就是把换行符\n改成\0。因为strlen是计算从开始到\0之前的长度,比如说一个字符串是 abc\n\0,那么strlen得到的是4,\n的下标位置是3.

client端:程序基本就是改了个顺序,先接收来自服务器端的数据,再发送数据

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/stat.h>
#include<sys/msg.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
#define SERVER_MSG 1
#define CLIENT_MSG 2    
int main(int argc,char **argv,char **environ){struct mymsgbuf{long msgtype;char ctrlstring[BUF_SIZE];}msgbuffer;int qid;int msglen;key_t msgkey;if((msgkey=ftok(PATH_NAME,PROJ_ID))==-1){perror("ftok error!\n");exit(1);}if((qid=msgget(msgkey,IPC_CREAT|0660))==-1){perror("msgget error!\n");exit(1);}while(1){if(msgrcv(qid,&msgbuffer,BUF_SIZE,SERVER_MSG,0)==-1){perror("Server msgrcv error!\n");exit(1);}printf("server:%s\n",msgbuffer.ctrlstring);printf("client: ");fgets(msgbuffer.ctrlstring,BUF_SIZE,stdin);if(strncmp("exit",msgbuffer.ctrlstring,4)==0){break;}msgbuffer.ctrlstring[strlen(msgbuffer.ctrlstring)-1]='\0';msgbuffer.msgtype=CLIENT_MSG;if(msgsnd(qid,&msgbuffer,strlen(msgbuffer.ctrlstring)+1,0)==-1){perror("client msgsnd error!\n");exit(1);}}exit(0);
}

先运行server程序,再在一个终端运行client程序,这样两个程序之间就可以进行聊天

这篇写了真的很久,内容超级多而且很杂,内容又很新,我自己学习也花了很久

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

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

相关文章

OPPO公布全新AI战略,AI 手机时代再提速

2024年2月20日&#xff0c;深圳——今日OPPO 举办 AI 战略发布会&#xff0c;分享新一代 AI 手机的四大能力特征&#xff0c;展望由AI驱动的手机全栈革新和生态重构的趋势&#xff0c;并发布由OPPO AI 超级智能体和 AI Pro 智能体开发平台组成的OPPO 1N 智能体生态战略&#xf…

Android基础Adapter适配器详解

一、概念 Adapter是后端数据和前端显示UI的适配器接口。常见的View如ListView、GridView等需要用到Adapter. BaseAdapter&#xff1a;抽象类&#xff0c;实际开发中继承这个类并且重写相关方法&#xff0c;用得最多的一个Adapter&#xff01; ArrayAdapter&#xff1a;支持泛型…

数字化商品管理:革新鞋服零售模式,引领智能商业新时代

随着科技的快速发展&#xff0c;数字化浪潮席卷各行各业&#xff0c;鞋服零售企业亦不例外。在这个新时代&#xff0c;数字化商品管理不仅成为鞋服零售企业革新的关键&#xff0c;更是其引领智能商业浪潮的重要引擎。本文将围绕数字化商品管理如何深刻影响鞋服零售模式&#xf…

力扣 309. 买卖股票的最佳时机含冷冻期

题目来源&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/ C题解&#xff1a;动态规划 状态1&#xff1a;表示持有股票。更新为之前持有股票&#xff08;dp[i-1][0]&#xff09;或者不持有股票且不处于冷冻期后买入&…

make_shared_for_overwrite

这个函数用来malloc数组&#xff0c;但不初始化。 不过这个仅限于内置类型。如果是用户写的&#xff0c;就会增加自动初始化&#xff08;调用客户写的初始化&#xff09;。

Java基于SSM的羽毛球馆管理系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

[word] word带圈数字20以上 #笔记#笔记

word带圈数字20以上 办公中有时候需要用到带圈数字&#xff0c;超过20的数字就不能直接编辑了&#xff0c;那么20以上带圈数字要怎么输入呢&#xff1f;其实通过小技巧就能完成的&#xff0c;接下来就给大家介绍下呢&#xff0c;一起看看吧&#xff01; 20以上带圈数字输入技巧…

Java Swing游戏开发学习1

不使用游戏引擎&#xff0c;只使用Java SDK开发游戏的学习。 游戏原理 图片来自某大佬视频讲解 原理结合实际代码 public class GamePanel extends Jpanel implements Runnable {...run(){}// 详情看下图... }项目结构 运行效果 代码code 在我的下载里面可以找到&#xf…

USART(串口发送接受单字节)

一、硬件 差分信号不需要太大的压差。在相同的电磁干扰的环境下&#xff0c;因为是双扭线&#xff0c;两根线受干扰的程度是一样的&#xff0c;所以压差相对不变。提高抗干扰能力。485是双绞线传输取的是两线的压差。一般来说受干扰后同步变化&#xff0c;比如都升0.5V或都降5…

PROBIS铂思金融破产后续:ASIC牌照已注销

2024年1月31日&#xff0c;PROBIS铂思金融的澳大利亚ASIC牌照 (AFSL 338241) 被注销《差价合约经纪商PROBIS宣布破产&#xff0c;澳大利亚金融服务牌照遭暂停》&#xff0c;这也就意味着&#xff0c;PROBIS铂思金融目前已经没有任何金融牌照。 值得注意的是&#xff0c;时至今日…

Python实现线性逻辑回归和非线性逻辑回归

线性逻辑回归 # -*- coding: utf-8 -*- """ Created on 2024.2.20author: rubyw """import matplotlib.pyplot as plt import numpy as np from sklearn.metrics import classification_report from sklearn import preprocessing from sklearn…

vmware升级处理vib包冲突的问题

一、问题截图 通过mgmt挂载iso: 通过vcenter升级的截图&#xff1a; 通过cli升级报错&#xff1a;二、解决办法 1、删除冲突的vib 2、重启后继续升级 三、解决步骤 1、查看那些vib冲突需要被清理 2、进行cli命令进行清理 esxcli software vib list | grep xxxx esxcli s…

hung task, soft lockup, hard lockup, workqueue stall

hung task&#xff0c;soft lockup&#xff0c;hard lockup&#xff0c;workqueue stall 是 linux 内核中的异常检测机制&#xff0c;这 4 个检测均是通过时间维度上的检测来判断异常。 在时间维度上的检测机制&#xff0c;有两个核心的点&#xff1a; &#xff08;1&#xff…

多个.C 文件关于全局变量如何使用

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

新 Mac 使用指南

文章目录 1、安装软件2、修改启动台3、修改 iCloud 设置、同步数据4、管理文件夹5、管理侧边栏6、设置快捷键 更新版本出现问题&#xff08;有机会更新下问题和解决方式&#xff09;&#xff0c;重装 Sonoma&#xff0c;获得了一个新的 macOS。以新用户的视角来看&#xff0c;有…

sora生成高质量视频的原理

Sora是怎样生成视频的&#xff1f; 写在前面 Sora 是 OpenAI 在日前发布的超强视频生成 AI&#xff0c;旨在探索 AI 如何在理解真实世界运动和交互方面做得更好Sora目前无灰度体验 面临挑战 Sora面对的挑战就像是需要处理和理解来自世界各地、不同设备拍摄的数以百万计的图…

Google账号批量注册指南:如何防止多账号被封?

电子邮件地址对于在线帐户至关重要&#xff0c;但它们可能被滥用于发送垃圾邮件。因此Google使用先进的算法来检测可疑的注册和验证尝试&#xff0c;保护用户免受垃圾邮件和其他有害活动的侵害&#xff0c;所以如果需要批量注册多个Google帐户&#xff0c;需要做好账号防关联&a…

初阶数据结构之---顺序表和链表(C语言)

引言-线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连续的一条直线。但在物理上并不一定是连续的。线性表在物理上…

机器学习 day38(有放回抽样、随机森林算法、XGBoost)

有放回抽样 有放回抽样和无放回抽样的区别&#xff1a;有放回可以确保每轮抽取的结果不一定相同&#xff0c;无放回则每轮抽取的结果都相同 在猫狗的例子中&#xff0c;我们使用”有放回抽样“来抽取10个样本&#xff0c;并组合为一个与原始数据集不同的新数据集&#xff0c;虽…

git push 使用 --mirror 参数复制仓库

迁移一个 Git 仓库并且保留原有的提交记录和分支 克隆原始仓库到本地 git clone <原始仓库URL> <新仓库目录>添加新的远程仓库&#xff1a;git remote add new-origin <新仓库URL>推送所有分支和标签到新的远程仓库&#xff1a;git push new-origin --mirro…