linux C -- 消息队列

linux C -- 消息队列

  • 前言
  • 一、System V(IPC)消息队列
      • 接口调用主要涉及到 msgget、msgsnd、msgrcv 和 msgctl 四个接口:
    • 1、创建消息队列 msgget
    • 2、发送消息到队列
    • 3、从队列接收信息
    • 4、控制消息队列 msgctl
    • 5、删除消息队列
  • 二、代码编写
    • 1、发送部分的代码
    • 2、代码完成后编译一下
    • 3、启动运行,传递第一个消息队列
    • 4、可以使用ipcs -q查看消息队列的信息
    • 5、接收部分的代码
    • 6、同样的编译然后运行
    • 7、代码封装
  • 三、POSIX(mq)消息队列
  • 附录

前言

进程间通信是linux下经常用到的通信方式,可用于多个进程之间的通信,也可在一个进程内通信。
消息队列就是一堆消息的有序集合(队列),并缓存于内核中。如此一来,多个进程就可通过访问内核来实现多个进程之间的通信。目前存在的消息队列有POSIX(mq)与System V(IPC)标准接口。

一、System V(IPC)消息队列

接口说明
消息缓冲区的结构定义一般如下:

struct msg_form {long mtype;//类型char mtext[];//消息内容,可以是定长数组或者变长数组
};

头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

接口调用主要涉及到 msgget、msgsnd、msgrcv 和 msgctl 四个接口:

1、创建消息队列 msgget

/**
函数:创建或获取消息队列 
入参:key:key可取由ftok创建的key值或1个整数;msgflag主要有两个值IPC_CREAT 和IPC_EXC,指的是需要新创建消息队列ID,低位可用来确定消息队列的访问权限。例如(IPC_CREAT | 0777)
返回:成功返回消息队列id,失败返回-1
**/
int msgget(key_t key, int msgflg)

2、发送消息到队列

/**
函数:发送消息到队列
入参:msqid:消息队列的ID(由msgget生成的消息队列标识符)msgp:msgq为指向的用户定义缓冲区,一般定义为结构体,首个成员为long型,表示消息的类型,另外一个一般为char mtext[];msgsz:发送消息正文的字节数,注意这里的是指正文内容mtext里面数据的字节数msgflg:标志位,IPC_NOWAIT消息没有发送完成函数也会立即返回,0 直到发送完成函数才返回
返回:成功返回0,错误返回-1
**/
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

3、从队列接收信息

/**
函数:发送消息到队列
入参:msqid:消息队列的ID(由msgget生成的消息队列标识符)msgp:读取到的数据要放到哪里,这里填我们自定义的结构体对象msgsz:要读取的正文字节数,是指正文内容mtext里面数据的字节数msgtyp:要读取的消息类型,mtype(默认用0)msgflg:标志位,IPC_NOWAIT非堵塞等待,0 堵塞等待   
返回:成功返回读取到的字节数,失败就返回-1,错误码被设置
**/
int msgrcv(int msgid, void * msgq, size_t msgsz, long int msgtyp, int msgflg)

进阶说明

/** 
msgtyp:=0 直接返回第一条消息(FIFO原理)>0 若msgflg不包含MSG_EXCEPT,则返回消息队列中第一个类型为msgtpy,若包含,则返回消息队列第一个类型为msgtpy<0 返回消息队列中类型≤msgtpy绝对值的消息,若多个,取最小msgflg: 不包含MSG_NOERROR,消息又太长,则不对该消息做任何处理直接返回-1包含MSG_NOERROR,则该消息被截取msgsz字节返回,剩余部分被丢弃
*/

4、控制消息队列 msgctl

/**
函数:发送消息到队列
入参:msqid:消息队列的ID(由msgget生成的消息队列标识符)cmd:IPC_STAT 将msg相关的内核信息存储到buf指向的msqid_ds 结构体中。IPC_SET 该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;IPC_RMID 删除msqid标识的消息队列buf:在标志位中设置了IPC_STAT,指针所指向的变量里面就能拿到相关的内核信息,如果不关心内核信息可以设置为nullptr
返回:成功返回0,错误返回-1
**/
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msqid_ds 这个结构体是比较复杂的,需要进阶的朋友可以自行了解

struct msqid_ds {struct ipc_perm msg_perm{   // 消息队列的权限信息key_t key;          	// 消息队列的键值uid_t uid;          	// 拥有者的用户IDgid_t gid;          	// 拥有者的组IDuid_t cuid;         	// 创建者的用户IDgid_t cgid;         	// 创建者的组IDmode_t mode;        	// 权限unsigned short seq; 	// 序列号}time_t msg_stime;            // 上次发送消息的时间time_t msg_rtime;            // 上次接收消息的时间time_t msg_ctime;            // 上次变更时间unsigned long msg_cbytes;    // 消息队列中的字节数msgqnum_t msg_qnum;          // 消息队列中的消息数量msglen_t msg_qbytes;         // 消息队列的最大字节数pid_t msg_lspid;             // 最后发送消息的进程IDpid_t msg_lrpid;             // 最后接收消息的进程ID
};

5、删除消息队列

IPC_RMID
立即删除消息队列,此时所有阻塞在对该消息队列的,msgsnd和msgrcv函数调用,
都会立即返回失败,errno为EIDRM

// 删除消息队列
if (msgctl(msqid, IPC_RMID, NULL) == -1) {perror("Error deleting message queue");return 1;
}

二、代码编写

1、发送部分的代码

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/msg.h>
#include <string.h>int main (void) {printf("创建消息队列...\n");key_t key = ftok(".",100);if(key == -1){perror("ftok");return -1;}int msgid = msgget(key,IPC_CREAT | 0777);if(msgid == -1){perror("msggeet");return -1;}printf("从消息队列(0x%08x/%d)中发送消息...\n",key,msgid);for(;;){struct {long mtype;char mtext[1024];}msgbuf;printf(">");gets(msgbuf.mtext);msgbuf.mtype = 1; //传输的消息类型是>0的整数ssize_t msgsz = msgsnd(msgid,(void*)&msgbuf,(strlen(msgbuf.mtext)+1)*sizeof(msgbuf.mtext[0]),IPC_NOWAIT);if (msgsz < 0) {if(errno == EIDRM) {printf("消息队列(0x%08x/%d)已被销毁!!!\n",key,msgid);break;}else {perror("msgsnd");return -1;}}else printf("%04ld<%s\n",msgsz,msgbuf.mtext);//消息回显}printf("结束了!\n");return 0;
}

2、代码完成后编译一下

在这里插入图片描述
使用ls查看一下

3、启动运行,传递第一个消息队列

在这里插入图片描述

4、可以使用ipcs -q查看消息队列的信息

在这里插入图片描述
● 我们发现msgid可以为0
● 消息队列中已经存储了一条消息了,但是还没人消费

5、接收部分的代码

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/msg.h>int main (void) {printf("获取消息队列...\n");key_t key = ftok(".",100);if(key == -1){perror("ftok");return -1;}int msgid = msgget(key,0);if(msgid == -1){perror("msggeet");return -1;}printf("从消息队列(0x%08x/%d)中接收消息...\n",key,msgid);for(;;){struct {long mtype;char mtext[1024];}msgbuf;ssize_t msgsz = msgrcv(msgid,(void*)&msgbuf,sizeof(msgbuf.mtext)-sizeof(msgbuf.mtext[0]),0,MSG_NOERROR);if (msgsz < 0) {if(errno == EIDRM) {printf("消息队列(0x%08x/%d)已被销毁!!!\n",key,msgid);break;}else {perror("msgrcv");return -1;}}else printf("%04ld<%s\n",msgsz,msgbuf.mtext);}printf("结束了!\n");return 0;
}

6、同样的编译然后运行

最终的效果就是这样了
在这里插入图片描述

7、代码封装

示例代码解析
● msg_que.h

/********************************
程序功能:进程通信-消息队列(system V)
author:zyh
date:2021.5.21
*********************************/#ifndef _MSG_QUE_H_
#define _MSG_QUE_H_#ifdef __cplusplus
extern "C" {#endif/*
注意:进程通信消息队列的总缓冲区大小有限制,传输的消息量比较多的时候,就不适合使用
在Linux中,/proc/sys/kernel/msgmax和/proc/sys/kernel/msgmnb文件记载了消息缓冲队列的大小
其中,kernel.msgmax表示消息大小的最大值,kernel.msgmnb表示消息缓冲区的最大值。
*///#define MSG_FILE "/tmp/msgque"  //进程通信共有的文件#define MAX_QUEUE_TEXT_LENGTH 1024*2  //发送消息最大长度struct msg_form {long mtype;//类型char mtext[MAX_QUEUE_TEXT_LENGTH];//消息};typedef enum { //类型(类型必须大于0)NONE = 0,TYPE_1_MSG,TYPE_2_MSG,TYPE_3_MSG,TYPE_4_MSG,TYPE_5_MSG,}MSG_QUE_TYPE;/**
函数功能:获取文件路径key值
入参: path:文件路径,例如:/tmp/msgque
出参:
返回:成功返回key值,失败返回-1
**/int get_path_key(const char *path);/**
函数功能:创建消息队列,返回消息队列的标识
入参: key:消息队列名
出参:无
返回:成功返回消息队列的标识,失败返回-1
**/int creatMsgQue(int key);/**
函数功能:消息队列的删除
入参:msqid:消息队列的标识 
出参:无
返回:成功返回0,失败返回-1
**/	int deleteMsgQue(int msgid);/**
函数功能:发送消息
入参:msgid:由msgget函数返回的消息队列的标识码,即将消息添加到那个消息队列中。type:消息类型msg:发送的消息length:消息长度
出参:无
返回:成功返回0,失败返回-1
**/int sndMsgQue(int msgid, int type, char *msg, int length);/**
函数功能:从消息队列中堵塞接收消息
入参:msgid:为读的对象,即从哪个消息队列获取的消息type:消息类型,0的话,函数将不做类型检查而自动返回队列中的最旧的消息。rcvBuf:接收消息缓冲区bufSize:接收消息缓冲区大小
出参:rcvBuf:接收消息的缓冲区
返回:成功返回接收到的实际字节数,失败返回-1
解除阻塞的条件有以下三个:
1、消息队列中有了满足条件的消息。
2、消息队列被删除。
3、用msgrcv()的进程被信号中断。
**/	int blockRcvMsgQue(int msgid, int type, char rcvBuf[], int bufSize);/**
函数功能:从消息队列中不堵塞接收消息
入参:msgid:为读的对象,即从哪个消息队列获取的消息type:消息类型,0的话,函数将不做类型检查而自动返回队列中的最旧的消息。rcvBuf:接收消息缓冲区bufSize:接收消息缓冲区大小
出参:rcvBuf:接收消息的缓冲区
返回:成功返回接收到的实际字节数,-1:消息队列为空
**/	int noBlockRcvMsgQue(int msgid, int type, char *rcvBuf, int bufSize);#ifdef __cplusplus
}
#endif#endif

● msg_que.c

/********************************
程序功能:进程通信-消息队列(system V)
author:zyh
date:2021.5.21
*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include "msg_que.h"/**
函数功能:获取文件路径key值
入参: path:文件路径,例如:/tmp/msgque
出参:
返回:成功返回key值,失败返回-1
**/
int get_path_key(const char *path)
{key_t key;//获取key值,key代表要创建的消息队列的标识, 即为ipc键key = ftok(path, 'z');if (0 > key) { //第一个参数代表路径,第二个参数代表权限只使用8bitsperror("ftok error");return -1;}return key;
}/**
函数功能:创建消息队列,返回消息队列的标识
入参: key:消息队列名
出参:无
返回:成功返回消息队列的标识,失败返回-1
**/
int creatMsgQue(int key)
{int msqid;/*key_t key;//获取key值,key代表要创建的消息队列的标识, 即为ipc键if((key = ftok(MSG_FILE,'z')) < 0) { //第一个参数代表路径,第二个参数代表权限只使用8bitsperror("ftok error");return -1;}*/printf("Message Queue - key is: %d\n", key);//创建消息队列,第一个参数 key:为由ftok创建的key值,第二个参数 msgflg:用来确定消息队列的访问权限。if (0 > (msqid = msgget(key, IPC_CREAT | 0777))) { //第二个参数 用来确定消息队列的访问权限。返回消息队列的标识 如果这个消息队列已经存在,则返回IDperror("msgget error");return -1;}return msqid;
}/**
函数功能:消息队列的删除
入参:msqid:消息队列的标识 
出参:无
返回:成功返回0,失败返回-1
**/	
int deleteMsgQue(int msgid)
{int ret = 0;ret = msgctl(msgid, IPC_RMID, NULL);if (0 > ret) {perror("msgctl");return -1;}return 0;
}/**
函数功能:发送消息
入参:msgid:由msgget函数返回的消息队列的标识码,即将消息添加到那个消息队列中。type:消息类型msgBuff:发送的消息length:消息长度
出参:无
返回:成功返回0,失败返回-1
**/	
int sndMsgQue(int msgid, int type, char *msg, int length)
{int ret = 0;struct msg_form msgbuf;memset(&msgbuf, 0, sizeof(msgbuf));if (length >= (int)sizeof(msgbuf.mtext)) {fprintf(stderr, "msg length is too long\n");return -1;}msgbuf.mtype = type;memcpy(msgbuf.mtext, msg, length);//ret = msgsnd(msgid, (void*)&msgbuf, sizeof(msgbuf) - sizeof(long), IPC_NOWAIT);//当队列满时不阻塞,立刻返回ret = msgsnd(msgid, (void*)&msgbuf, length, IPC_NOWAIT);//当队列满时不阻塞,立刻返回if (0 > ret) {perror("msgsnd");return -1;}return 0;
}/**
函数功能:从消息队列中堵塞接收消息
入参:msgid:为读的对象,即从哪个消息队列获取的消息type:消息类型,0的话,函数将不做类型检查而自动返回队列中的最旧的消息。rcvBuf:接收消息缓冲区bufSize:接收消息缓冲区大小
出参:rcvBuff:接收消息的缓冲区
返回:成功返回接收到的实际字节数,失败返回-1
解除阻塞的条件有以下三个:
1、消息队列中有了满足条件的消息。
2、消息队列被删除。
3、用msgrcv()的进程被信号中断。
**/	
int blockRcvMsgQue(int msgid, int type, char rcvBuf[], int bufSize)
{int ret = 0;struct msg_form msgbuf;memset(&msgbuf, 0, sizeof(msgbuf));ret = msgrcv(msgid, (void*)&msgbuf, sizeof(msgbuf) - sizeof(long), type, 0);//没有指定IPC_NOWAIT,进程阻塞,挂起执行直至有了指定类型的消息if (0 > ret) {perror("msgrcv");return -1;}//printf("rcv size ret=%d\n", ret);//memcpy(rcvBuf, msgbuf.mtext, ret);memcpy(rcvBuf, msgbuf.mtext, bufSize);return ret;
}/**
函数功能:从消息队列中不堵塞接收消息
入参:msgid:为读的对象,即从哪个消息队列获取的消息type:消息类型,0的话,函数将不做类型检查而自动返回队列中的最旧的消息。rcvBuff:接收消息缓冲区rcvSize:接收消息缓冲区大小
出参:rcvBuff:接收消息的缓冲区
返回:成功返回接收到的实际字节数,-1:消息队列为空
**/	
int noBlockRcvMsgQue(int msgid, int type, char *rcvBuf, int bufSize)
{int ret = 0;struct msg_form msgbuf;memset(&msgbuf, 0, sizeof(msgbuf));ret = msgrcv(msgid, (void*)&msgbuf, sizeof(msgbuf) - sizeof(long), type, IPC_NOWAIT);//不阻塞,如果消息队列为空,则返回一个ENOMSGif (0 > ret) {//perror("msgrcv");return -1;}//printf("rcv size ret=%d\n", ret);memcpy(rcvBuf, msgbuf.mtext, bufSize);return ret;
}

● send_demo.c-发送端(发送两种类型的数据)

/********************************
程序功能:进程通信
author:zyh
date:2021.5.21
*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "msg_que.h"#define MSG_QUE_KEY_ID 45464 //消息队列标识
int main () 
{int msgid = -1;char msgBuff[256] = {0};int i = 0;msgid = creatMsgQue(MSG_QUE_KEY_ID);if (0 > msgid) {printf("start msgQue failed\n");return -1;}printf("start msgQue success (msgid=%d)\n", msgid);while (1) {sprintf(msgBuff, "TYPE_1_MSG:%d", i);sndMsgQue(msgid, 1, msgBuff, strlen(msgBuff));sprintf(msgBuff, "TYPE_2_MSG:%d", i);sndMsgQue(msgid, 2, msgBuff, strlen(msgBuff));i++;sleep(2);}deleteMsgQue(msgid);return 0;
}

● recv1_demo.c 接收端接收类型1的数据

/********************************
程序功能:进程通信
author:zyh
date:2021.5.21
*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "msg_que.h"#define MSG_QUE_KEY_ID 45464 //消息队列标识
int main () 
{int msgid = -1;char rcvBuff[256] = {0};msgid = creatMsgQue(MSG_QUE_KEY_ID);if (0 > msgid) {printf("start msgQue failed\n");return -1;}printf("start msgQue success (msgid=%d)\n", msgid);while (1) {memset(rcvBuff, 0, sizeof(rcvBuff));blockRcvMsgQue(msgid, 1, rcvBuff, sizeof(rcvBuff));printf("TYPE_1_MSG:%s\n", rcvBuff);}deleteMsgQue(msgid);return 0;
}

三、POSIX(mq)消息队列

直接使用系统接口:
编译指令gcc mq_test.c -o test -Wall -lrt

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>typedef struct {int a;int b;char str[32];
} my_data_t;/*
- 我们首先打开一个进程通信--POSIX (mq)消息队列,如果它不存在,我们会创建一个。这是通过指定O_CREAT标志实现的。
- 我们设置消息队列的属性,包括队列的最大消息数,每个消息的最大长度,以及队列当前的消息数。
- 我们在mq_receive()调用中传递一个指向存储消息的缓冲区的指针。如果当前没有消息,此调用将会阻塞,直到接收到一个消息。为了进行非阻塞接收,可以在打开消息队列时设置mq_flags字段为O_NONBLOCK。
- 用mq_close关闭消息队列和mq_unlink删除消息队列是有序执行,因为直到所有使用此队列的进程都关闭后,队列才可以被删除
*/
int main()
{mqd_t mqd;struct mq_attr attr;attr.mq_flags = O_NONBLOCK;    /*0或O_NONBLOCK,0堵塞,O_NONBLOCK为非阻塞 */attr.mq_maxmsg = 128;  /* 队列最大消息数 */attr.mq_msgsize = 256;  /* 队列每个消息的最大长度 */attr.mq_curmsgs = 0;  /* 队列当前消息数 *///1. 创建或打开消息队列mqd = mq_open("/mq_name", O_CREAT | O_RDWR, 0644, &attr);//必须以/开头,并且后续不能有其他/,形如/abcif (0 > mqd) {perror("mq_open");return -1;}mq_getattr(mqd, &attr);//获取mqd指向的消息队列的属性,存放到attr结构体,成功:0,出错:-1printf("attr.mq_curmsgs = %ld\n", attr.mq_curmsgs);/*2. 发送消息prio:消息的优先级:它是一个小于MQ_PRIO_MAX的数,数值越大,优先级越高。posix消息队列在调用mq_receive时,总是返回队列中最高优先级的最早消息。如果消息不需要设定优先级,那么可以在mq_send时设置msg_prio为0,mq_receive的msg_prio设置为NULL。*/char msg[256] = "hello";int prio = 0;mq_send(mqd, msg, strlen(msg), prio);//如果队列已满,在堵塞模式下,将阻塞,直到队列未满,成功返回0,失败返回-1//发送自定义结构体my_data_t data = {1, 2, "zhou"};mq_send(mqd, (char *)&data, sizeof(data), prio);//mq_getattr(mqd, &attr);//获取mqd指向的消息队列的属性,存放到attr结构体,成功:0,出错:-1printf("attr.mq_curmsgs = %ld\n", attr.mq_curmsgs);//3. 接收消息char buffer[256] = {0};int rcv_bytes = 0;/*msg_len参数要大于等于mq_msgsize的,如果小于该值,就会返回EMSGSIZE错误;如果队列为空,在堵塞模式下,将阻塞直到有消息为止, 返回指定消息队列中最高优先级的最早消息,成功返回读取消息的内容的字节数,出错返回-1*/rcv_bytes = mq_receive(mqd, buffer, attr.mq_msgsize, NULL);printf("rcv_bytes=%d, buffer=%s\n", rcv_bytes, buffer);my_data_t rcv_data = {0};rcv_bytes = mq_receive(mqd, (char *)&rcv_data, attr.mq_msgsize, NULL);printf("rcv_data.a=%d, rcv_data.b=%d, rcv_data.str=%s\n", rcv_data.a, rcv_data.b, rcv_data.str);//4. 关闭消息队列mq_close(mqd);  /* 关闭消息队列 */mq_unlink("/mq_name");  /* 删除消息队列 */
}

附录

链接: 学习笔记

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

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

相关文章

BYOL(NeurIPS 2020)原理解读

paper&#xff1a;Bootstrap your own latent: A new approach to self-supervised Learning third-party implementation&#xff1a;https://github.com/open-mmlab/mmpretrain/blob/main/mmpretrain/models/selfsup/byol.py 本文的创新点 本文提出了一种新的自监督学习方…

uniapp picker 多列选择器用法

uniapp picker 多列选择器联动筛选器交互处理方法&#xff0c; uniapp 多列选择器 mode"multiSelector" 数据及筛选联动交互处理&#xff0c; 通过接口获取数据&#xff0c;根据用户选择当前列选项设置子列数据&#xff0c;实现三级联动效果&#xff0c; 本示例中处…

SEW减速机参数查询 2-2 实践

首先说说结论&#xff1a;在不和SEW官方取得沟通之前&#xff0c;你几乎无法直接通过查阅SEW官方文档得到相关减速机的所有技术参数&#xff1a;比如轴的模数和齿数&#xff0c;轴承的参数。我在周一耗费了一个上午&#xff0c;最终和SEW方面确认后才知晓相关技术参数需要凭借销…

Jenkins的安装和部署

文章目录 概述Jenkins部署项目的流程jenkins的安装启动创建容器进入容器浏览器访问8085端口 Jenkins创建项目创建example项目 概述 Jenkins&#xff1a;是一个开源的、提供友好操作界面的持续集成&#xff08;CLI&#xff09;工具&#xff0c;主要用于持续、自动构建的一些定时…

什么是Rust语言?探索安全系统编程的未来

&#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来 文章目录 &#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来摘要引言正文&#x1f4d8; Rust语言简介&#x1f31f; 发展历程&#x1f3af; Rust的技术意义和优势&#x1f4e6; Rust解决的问题…

电商技术揭秘三十:知识产权保护浅析

电商技术揭秘相关系列文章&#xff08;上&#xff09; 相关系列文章&#xff08;中&#xff09; 电商技术揭秘二十&#xff1a;能化供应链管理 电商技术揭秘二十一:智能仓储与物流优化(上) 电商技术揭秘二十二:智能仓储与物流优化(下) 电商技术揭秘二十三&#xff1a;智能…

deepinV23 Beta3安装cuda

文章目录 下载CUDA安装,以cuda11.6为例运行.run文件安装选项配置环境变量查看cuda版本重启计算机 卸载cuda deepinV23 Beta3对应的debian版本是12&#xff1a; bookworm指的是debian12&#xff0c; sid代表不稳定版。 下载CUDA 官网&#xff1a;https://developer.nvidia.com…

中华环保联合会获得国家“绿色制造体系” 第三方评价机构资格

近日&#xff0c;中华环保联合会成功获得工业和信息化部“绿色制造体系”第三方评价机构资格&#xff0c;可为企业、园区及相关机构提供全面的绿色制造体系评价服务&#xff0c;包括绿色工厂、绿色园区、绿色供应链等方面。 “绿色制造体系建设”是由工业和信息化部负责统筹推进…

redis异常:OOM command not allowed when used memory > ‘maxmemory‘

redis存储数据太多,内存溢出,导致异常 1.查看redis内存使用情况 登录redis后 info memory2.查看分配给redis的最大内存 config get maxmemory3.处理方式:拓展redis的最大内存 打开redis.conf文件,修改maxmemory 4.删掉键值重启redis后,发现删掉的数据又恢复了? redis根目录…

Midjourney是什么?Midjourney怎么用?怎么注册Midjourney账号?国内怎么使用Midjourney?多人合租Midjourney拼车

Midjourney是什么 OpenAI发布的ChatGPT4引领了聊天机器人的竞争浪潮&#xff0c;随后谷歌推出了自己的AI聊天机器人Bard&#xff0c;紧接着微软推出了Bing Chat&#xff0c;百度也推出了文心一言&#xff0c;这些聊天机器人的推出&#xff0c;标志着对话式AI技术已经达到了一个…

月球地形数据介绍(LOLA)

月球地形数据介绍 LOLA介绍LOLA数据的处理与发布数据类型和格式投影坐标系SIMPLE CYLINDRICALPOLAR STEREOGRAPHIC 数据下载与浏览 LOLA介绍 目前最新的月球地形高程数据来源于美国2009年发射的LRO探测器。 “月球勘测轨道器”(Lunar Reconnaissance Orbiter&#xff0c;LRO)…

7.2 跳跃表(skiplist)

文章目录 前言一、跳跃表——查找操作二、跳跃表——插入操作三、代码演示3.1 输出结果3.2 代码细节 四、总结&#xff1a;参考文献&#xff1a; 前言 本章内容参考海贼宝藏胡船长的数据结构与算法中的第七章——查找算法&#xff0c;侵权删。 查找的时间复杂度能从原来链表的…

线上真实案例之执行一段逻辑后报错Communications link failure

1.问题发现 在开发某个项目的一个定时任务计算经销商返利的功能时&#xff0c;有一个返利监测的调度&#xff0c;如果某一天返利计算调度失败了&#xff0c;需要重新计算&#xff0c;这个监测的调度就会重新计算某天的数据。 在UAT测试通过&#xff0c;发布生产后&#xff0c…

CSS动画(css、js动画库:各种动画效果)

第一种方法&#xff1a;文字从上到下显示动画&#xff1b; <div class"text-container"><div class"text">文字从上到下显示</div></div><style scoped> /*确保 keyframes 规则在引用它的任何选择器之前定义&#xff0c;以避…

Android开发:应用百度智能云中的身份证识别OCR实现获取个人信息的功能

百度智能云&#xff1a; 百度智能云是百度提供的公有云平台&#xff0c;于2015年正式开放运营。该平台秉承“用科技力量推动社会创新”的愿景&#xff0c;致力于将百度在云计算、大数据、人工智能的技术能力向社会输出。 百度智能云为金融、城市、医疗、客服与营销、能源、制造…

C语言数据结构之顺序表

目录 1.线性表2.顺序表2.1顺序表相关概念及结构2.2增删查改等接口的实现 3.数组相关例题 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性&#xff08;数据类型相同&#xff09;的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff…

2024年阿里云服务器明细报价整理总结

2024年阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核4G服务…

Zynq 7000 SoC器件的复位系统

Zynq7000 SoC器件中的复位系统包括由硬件、看门狗定时器、JTAG控制器和软件生成的复位。每个模块和系统都包括一个由复位系统驱动的复位。硬件复位由上电复位信号&#xff08;PS_POR_B&#xff09;和系统复位信号&#xff08;PS_SRST_B&#xff09;驱动。 在PS中&#xff0c;有…

JAVA基础面试题(第九篇)中! 集合与数据结构

JAVA集合和数据结构也是面试常考的点&#xff0c;内容也是比较多。 在看之前希望各位如果方便可以点赞收藏&#xff0c;给我点个关注&#xff0c;创作不易&#xff01; JAVA集合 11. HashMap 中 key 的存储索引是怎么计算的&#xff1f; 首先根据key的值计算出hashcode的值…

隧道代理的优势与劣势分析

“随着互联网的快速发展&#xff0c;网络安全已经成为一个重要的议题。为了保护个人和组织的数据&#xff0c;隧道代理技术逐渐成为网络安全的重要工具。隧道代理通过在客户端和服务器之间建立安全通道&#xff0c;加密和保护数据的传输&#xff0c;有效地防止黑客入侵和信息泄…