0807|IO进程线程day9 IPC对象概念及示例(消息队列、共享内存、信号灯集)

news2025/1/19 20:21:03

 0 什么是IPC机制

概念:        

        IPC机制:Inter Process Communication,即进程间通信机制。

        进程与进程间的用户空间相互独立,内核空间共享。所以如果要实现进程间的通信,需要使用进程间通信机制。

分类(3类):

  1. 传统的进程间通信机制
        无名管道  pipe
        有名管道  fifo
        信号      signal
  2. system v操作系统的IPC对象
        消息队列  message queue
        共享内存  shared memory
        信号灯集  semaphore
  3. 可用于跨主机传输的通信
        套接字  socket

一、消息队列(message queue)

1.1 消息队列的概念

1) 消息队列的原理

   消息队列是在内核中创建一个容器(队列),进程需要将数据打包成结点,添加到队尾。或者从队列中读取结点,实现进程间通信。

2) 消息队列的特点

  1. 消息队列是面向记录的,其中消息具有特定的格式以及优先级。
  2. 消息队列总体上是根据先进先出的原则来实现读取的,也可以选择消息的类型后,按照先进先出的原则读取。
  3. 消息队列独立于进程。等进程结束后,消息队列以及其中的内容不会消失,依然存在,除非手动删除,或者重启操作系统。

3) 查看消息队列

查看消息队列: ipcs
                          ipcs -q
              
删除消息队列:ipcrm -q  msqid

1.2 消息队列的函数

1) ftok【计算键值】

功能:

        ① 该函数通过pathname提供的id,以及proj_id提供的8bit的值,计算key值(键值),给msgget shmget semget函数使用.

        ② 只要pathname和proj_id一致,则计算的key值就一致。那么通过相同key值找到的IPC对象就是同一个。

原型:

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

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

参数:

    char *pathname:文件的路径以及名字; 该文件必须存在且可访问
    int proj_id:传入一个非0参数;

返回值:

        成功,返回计算得到的key值;

        失败,返回-1,更新errno;

2) msgget【通过key在内核内存中找到对应的消息队列,并返回队列id】

功能:通过key值到内核内存中找对应的消息队列,并返回消息队列的id--->msqid;

原型:

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

       int msgget(key_t key, int msgflg);

参数:

    key_t keyftok函数返回出来的key值;
    int msgflg

  • IPC_CREAT:若消息队列不存在,则创建消息队列。若消息队列存在,则忽略该选项;
  • IPC_CREAT|0664:创建的同时指定消息队列的权限。
  • IPC_CREAT|IPC_EXCL:若消息队列不存在,则创建消息队列。若消息队列存在,则报错;

返回值:

        >=0, 成功返回消息队列的id号 msqid;

        =-1, 函数运行失败,更新errno;

3) msgsnd【打包数据发送到队列】

功能:将数据打包后发送到消息队列中;

原型:

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

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

参数:

    int msqid   :指定要发送到哪个消息队列中;
    void *msgp:指定要发送的消息包的首地址;

    通用格式如下:
    struct msgbuf 
    {
        long mtype;       /* message type, must be > 0 */    消息类型,必须大于0;
        char mtext[1];    /* message data */  消息内容,类型根据需求修改,想要发什么类型就填什么类型。
                                              大小与下一个参数msgsz指定的一致
    };   

    size_t msgsz:消息内容的大小,以字节为单位。   
    int msgflg

  • 0:阻塞方式发送,当消息队列满了,则当前函数阻塞;
  • IPC_NOWAIT:非阻塞方式,当消息队列满了,该函数不阻塞,且函数运行失败,errno == EAGAIN.

返回值:

        =0, 函数运行成功;

        =-1, 函数运行失败,更新errno;

练习:将数据发送至消息队列中,当类型位0时停止输入

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

struct msgbuf
{
    long mtype;
    char mtext[128];
};

int main(int argc, const char *argv[])
{
    //创建消息队列
    //创建key值
    key_t key =ftok("/home/ubuntu/IO/05_IPC/04_msg/",1);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    printf("key = %#x\n",key);

    //创建消息队列
    int msqid = msgget(key,IPC_CREAT|0664);
    if(msqid < 0)
    {
        perror("msgget");
        return -1;
    }
    printf("msqid = %d\n",msqid);

    struct msgbuf sndbuf;
    while(1)
    {
        printf("请输入消息类型 >>> ");                                        
        scanf("%ld",&sndbuf.mtype);
        getchar();
        if(0 == sndbuf.mtype)
            break;

        printf("请输入消息内容 >>> ");
        fgets(sndbuf.mtext,sizeof(sndbuf.mtext),stdin);
        sndbuf.mtext[strlen(sndbuf.mtext)-1]=0;

        //向消息队列中发送消息
        if(msgsnd(msqid,&sndbuf,sizeof(sndbuf.mtext),0) < 0)
        {
            perror("msgsnd");
            return -1;
        }
        printf("发送成功\n");
        system("ipcs -q");//让c代码执行shell命令
    }


    return 0;
}
                                                                              
                                                                              

4) msgrcv【从消息队列中读取数据】

功能:从消息队列中读取数据;

原型:

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>
       
       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
 int msgflg);

参数:

    int msqid   :指定要发送到哪个消息队列中;
    void *msgp:指定要发送的消息包的首地址;

    通用格式如下:
    struct msgbuf 
    {
        long mtype;       /* message type, must be > 0 */    消息类型,必须大于0;
        char mtext[1];    /* message data */  消息内容,类型根据需求修改,想要发什么类型就填什么类型。
                                              大小与下一个参数msgsz指定的一致
    };   


    size_t msgsz:消息内容的大小,以字节为单位。   
    long msgtyp :指定要读取的消息类型;

    msgtyp == 0, 读取消息队列中的第一条消息; 先进先出;
    msgtyp > 0,  指定消息类型读取,读取消息队列中第一条消息类型为 msgtyp参数指定的消息;
                 msgflg指定了MSG_EXCEPT,读取消息队列中第一条消息类型 不等于 msgtyp参数指定的消息;
                 vi -t MSG_EXCEPT;   #define MSG_EXCEPT      020000 
    msgtyp < 0,  读取消息队列中第一条最小的,且类型小于等于 msgtyp参数绝对值的消息。         

   int msgflg

        0:阻塞方式,当消息队列中没有消息了,该函数阻塞; 

        IPC_NOWAIT:非阻塞方式运行,当消息队列中没有消息了,该函数不阻塞,运行失败,errno == ENOMSG;

返回值:

        >0, 成功读取到的字节数;

        =-1, 函数运行失败,更新errno;

代码示例:

若消息队列中有消息:
    mtype 100   101  99   100  101
    mtext aaa   bbb  ccc  ddd  eee
i. msgtyp == 0
    while(1)                                                                   
    {
        //阻塞方式读取消息队列中第一条消息,先进先出的原则
        //res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), 0, 0);
        
        //非阻塞方式读取消息队列中第一条消息,先进先出的原则
        res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), 0, IPC_NOWAIT);
        if(res < 0)
        {
            perror("msgrcv");
            return -1;
        }
        printf("res=%ld : %ld %s\n", res, rcv.mtype, rcv.mtext);
    }
​
输出顺序:
    100 aaa   101 bbb   99 ccc   100 ddd    101 eee
ii. msgtyp > 0
    while(1)
    {
        //1.阻塞方式读取消息队列中第一条消息类型 == 101 的消息
        //res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), 101, 0);
​
        //2.非阻塞方式读取消息队列中第一条消息 == 101 的消息
        //res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), 101, IPC_NOWAIT);
                                                                                  
        //3.非阻塞方式读取消息队列中第一条消息类型 != 101的消息 
        res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), 101, IPC_NOWAIT|020000);
        if(res < 0)
        {
            perror("msgrcv");
            return -1;
        }
        printf("res=%ld : %ld %s\n", res, rcv.mtype, rcv.mtext);
    }
注释1,2的现象:
    101 bbb     101 eee
第3个的现象:
    100 aaa    99 ccc   100 ddd  
iii. msgtyp
    while(1)
    {
        //阻塞方式读取消息队列中<=msgtyp参数指定的消息类型中最小的那条消息;
        res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), -100, 0);
       
        //非阻塞方式读取消息队列中<=msgtyp参数指定的消息类型中最小的那条消息;
        //res = msgrcv(msqid, &rcv, sizeof(rcv.mtext), -100, IPC_NOWAIT);
​
        if(res < 0)
        {
            perror("msgrcv");
            return -1;
        }
        printf("res=%ld : %ld %s\n", res, rcv.mtype, rcv.mtext);
    }
​现象:
res=128 : 99 ccc
res=128 : 100 aaa
res=128 : 100 ddd
​

5) msgctl【控制消息队列,用于删除消息队列】

功能:控制消息队列,常用于删除消息队列;

原型:

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

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

参数:

        ​​​​​​int msqid   :指定要控制的消息队列的id号;
        int cmd

    IPC_STAT:获取消息队列的属性,属性存储在第三个参数中;
    IPC_SET:设置消息队列属性,属性存储在第三个参数中;
    IPC_RMID:删除消息队列,第三个参数无效,填NULL即可;

返回值:

        成功,返回0;

        失败,返回-1,更新errno

常用示例:

    //删除消息队列
    if(msgctl(msqid, IPC_RMID, NULL) < 0)
    {
        perror("msgctl");
        return -1;
    }
    printf("删除消息队列成功\n");

6) 作业

1. 要求用消息队列实现AB进程对话

  • A进程先发送一句话给B进程,B进程接收后打印
  • B进程再回复一句话给A进程,A进程接收后打印
  • 重复1.2步骤,当收到quit后,要结束AB进程

2. 实现随时收发:用多进程 多线程。

二、共享内存(shared memory)

2.1 共享内存的概念

1) 共享内存的原理

        在内核内存中创建一个共享内存,共享内存可以被分别映射到不同的进程的用户空间中,每个进程在各自的用户空间中就可以操作同一个共享内存,从而可以操作同一个物理地址空间。

2) 共享内存的特点

① 共享内存是 最高效的 进程间通信方式。

  • 进程可以在用户空间,通过指针直接访问共享内存,对共享内存进行读写,不需要任何的数据拷贝。

② 共享内存是在内核空间中被创建,可以被映射到不同的进程中。

③ 多个进程可以同事访问共享内存,因此对于共享内存的操作,需要引入进程的同步互斥机制:信号灯集

④ 共享内存独立于进程,即使进程结束,共享内存及其中的数据依然存在,除非手动删除或者重启操作系统。

⑤ 共享内存中的数据即使被读取后,依然存在,不会被删除。

3) 查看共享内存

查看共享内存:ipcs
              ipcs -m   
删除共享内存:ipcrm -m  shmid

2.2 共享内存的函数

1) ftok【计算键值】

功能:① 该函数通过pathname提供的id,以及proj_id提供的8bit的值,计算key值(键值),给msgget shmget semget函数使用.

          ② 只要pathname和proj_id一致,则计算的key值就一致。那么通过相同key值找到的IPC对象就是同一个。

原型:

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

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

参数:

    char *pathname:文件的路径以及名字; 该文件必须存在且可访问
    int proj_id:传入一个非0参数;

返回值:

        成功,返回计算得到的key值;

        失败,返回-1,更新errno;

2) shmget【通过key在内核内存中找到对应的消息队列,并返回队列id】

功能:通过key值到内核内存中找对应的共享内存,并返回共享内存的id--->msqid;

原型:

       #include <sys/ipc.h>
       #include <sys/shm.h>

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

参数:

    key_t key ftok函数返回出来的key值;

    ssize_t 指定要申请多少个字节的共享内存;
    int shmflg

  • IPC_CREAT:若共享内存不存在,则创建共享内存。若共享内存存在,则忽略该选项;
  • IPC_CREAT|0664:创建的同时指定共享内存的权限。
  • IPC_CREAT|IPC_EXCL:若共享内存不存在,则创建共享内存。若共享内存存在,则报错;

返回值:

        >=0, 成功返回共享内存的id号 shmid;

        =-1, 函数运行失败,更新errno;

3) shmat【将共享内存映射到用户空间中】

功能:将共享内存映射到用户空间中;

原型:

       #include <sys/types.h>
       #include <sys/shm.h>

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

参数:

    int shmid   :指定要映射的共享内存id号;
    const void *shmaddr 

        指定共享内存要映射到用户空间的位置,填对应空间的首地址; 例如:(void*)0x10

        填NULL,代表让操作系统自动映射;
    int shmgflg

  • 0:默认方式映射,进程对共享内存可读可写;
  • SHM_RDONLY:只读,进程对共享内存只读;

返回值:

        成功,返回共享内存映射到用户空间的首地址;

        失败,返回 (void *) -1,更新errno;

注意:

        获取到的映射空间的首地址的指向不允许修改,若修改后会导致首地址找不到,导致内存泄漏,与堆空间首地址不能改变的概念一致

4) shmdt【断开映射】

功能:将共享内存与进程的用户空间断开映射;

           当进程不想操作共享内存的时候,就可以断开映射

原型:

       #include <sys/types.h>
       #include <sys/shm.h>

 
       int shmdt(const void *shmaddr);

参数:

    void *shmaddr 指定要断开映射的用户空间的首地址;

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

5) shmctl【控制共享内存,常用于删除共享内存】

功能:通过key值到内核内存中找对应的共享内存,并返回共享内存的id--->msqid;

原型:

       #include <sys/ipc.h>
       #include <sys/shm.h>

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

参数:

   ​​​​​​int msqid   :指定要控制的消息队列的id号;
   int cmd

    IPC_STAT:获取消息队列的属性,属性存储在第三个参数中;
    IPC_SET: 设置消息队列属性,属性存储在第三个参数中;
    IPC_RMID:删除消息队列,第三个参数无效,填NULL即可;

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

6) 常用示例

    //删除共享内存
    if(shmctl(shmid, IPC_RMID, NULL) < 0)
    {
        perror("shmctl");
        return -1;
    }
    printf("删除共享内存成功\n");

7) 函数使用示例

写入

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
    //创建key值                                             
    key_t key = ftok("./",10);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    printf("key = %#x\n",key);

    //创建共享内存,获得shmid号
    int shmid = shmget(key, 32, IPC_CREAT|0664);
    if(shmid < 0)
    {
        perror("shmget");
        return -1;
    }
    printf("shmid = %d\n",shmid);

    //映射共享内存到用户空间
    void* addr= shmat(shmid, NULL, 0);
    if((void*)-1 == addr)
    {
        perror("shmat");
        return -1;
    }
    printf("addr = %p\n",addr);

    //先往共享内存中存储一个int类型数据
    //再在int类型数据后面存储一个字符串
    *(int*)addr=10;
    strcat((char*)addr+4,"hello world");
    //*(char*)addr+4="hello world";


    system("ipcs -m");
    return 0;
}

读取

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
    //创建key值
    key_t key = ftok("./",10);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    printf("key = %#x\n",key);

    //创建共享内存,获得shmid号
    int shmid = shmget(key, 32, IPC_CREAT|0664);
    if(shmid < 0)
    {
        perror("shmget");
        return -1;
    }
    printf("shmid = %d\n",shmid);

    //映射共享内存到用户空间
    void* addr= shmat(shmid, NULL, 0);
    if((void*)-1 == addr)
    {                                             
        perror("shmat");
        return -1;
    }
    printf("addr = %p\n",addr);

    //先往共享内存中存储一个int类型数据
    //再在int类型数据后面存储一个字符串
    printf("%d",*(int*)addr);
    printf("%s\n",(char*)addr+4);

    system("ipcs -m");
    return 0;
}

结果:

 

8) 作业

1.要求在共享内存中存入字符串 “1234567”。A进程循环打印字符串,B进程循环倒置字符串,要求结果不允许出现乱序:

        提示:共享内存中存储 flag + string.

三、信号灯集(semaphore)

3.1 信号灯集的概念

1)信号灯集的原理

2)信号灯集的核心操作

3.2 信号灯集的函数

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

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

相关文章

资深测试总结,Web自动化测试POM设计模式封装框架,看这篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 线性脚本 import…

Maven分模块-继承-聚合-私服的高级用法

Maven分模块-继承-聚合-私服的高级用法 JavaWeb知识&#xff0c;介绍Maven的高级用法&#xff01;&#xff01;&#xff01; 文章目录 Maven分模块-继承-聚合-私服的高级用法1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承…

服了呀,现在的00后,实在是太卷了

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

收藏这8个好用的原型设计工具,轻松制作原型图

在设计工作中&#xff0c;原型设计是非常关键的一步&#xff0c;而原型设计工具又能帮助设计师更轻松地完成设计工作。今天本文将与大家分享8个好用的原型设计工具&#xff0c;一起来看看吧&#xff01; 1、即时设计 即时设计是一个能在线协作的原型工具&#xff0c;也就是说…

DataGrip 配置 HiveServer2 远程连接访问

文章目录 集群配置 HiveServer2 服务DataGrip 配置 HiveServer2 访问 Hive 集群配置 HiveServer2 服务 1.在 Hive 的配置文件 hive-site.xml 中添加如下参数&#xff1a; <!-- 指定 HiveServer2 运行端口&#xff0c;默认为&#xff1a;10000 --><property><na…

ELK日志分析系统简介

ELK日志分析系统简介 ElasticsearchLogstashKibana主要功能Kibana日志处理步骤ELK的工作原理 日志服务器 提高安全性 集中存放日志 缺陷 ​ 对日志的分析困难 ELK日志分析系统 Elasticsearch 概述:提供了一个分布式多用户能力的全文搜索引擎 核心概念 接近实时 集群 节…

关于安卓jar包修改并且重新发布

背景&#xff1a; 对于某些jar包&#xff0c;其内部是存在bug的&#xff0c;解决的方法无外乎就有以下几种方法&#xff1a; &#xff08;1&#xff09;通过反射&#xff0c;修改其赋值逻辑 &#xff08;2&#xff09;通过继承&#xff0c;重写其方法 &#xff08;3&#xff0…

SQL-每日一题【1164. 指定日期的产品价格】

题目 产品数据表: Products 写一段 SQL来查找在 2019-08-16 时全部产品的价格&#xff0c;假设所有产品在修改前的价格都是 10 。 以 任意顺序 返回结果表。 查询结果格式如下例所示。 示例 1: 解题思路 1.题目要求我们查找在 2019-08-16 时全部产品的价格&#xff0c;假设所…

【Kubernetes】Kubernetes之Kubeadm部署

Kubeadm 一、Kubeadm 部署1. 环境准备2. 所有节点安装 docker3. 所有节点安装 kubeadm&#xff0c;kubelet 和 kubectl4. 部署 K8S 集群4.1 配置 master01 节点4.2 配置 node 节点 二、Kubeadm 高可用部署1. 环境准备2. 所有节点安装 docker2. 所有节点安装kubeadm&#xff0c;…

【大数据】Flink 详解(一):基础篇

Flink 详解&#xff08;一&#xff09;&#xff1a;基础篇 1、什么是 Flink &#xff1f; Flink 是一个以 流 为核心的高可用、高性能的分布式计算引擎。具备 流批一体&#xff0c;高吞吐、低延迟&#xff0c;容错能力&#xff0c;大规模复杂计算等特点&#xff0c;在数据流上提…

如何搭建一个成功的酒店小程序?

随着移动互联网的发展&#xff0c;小程序成为了不可忽视的商业工具之一。对于酒店行业来说&#xff0c;开发一个酒店预订小程序可以为客户提供更加便捷的预订方式&#xff0c;同时也带来了更多的商机。下面&#xff0c;我们将介绍一个简单的搭建流程&#xff0c;帮助新手快速上…

公会发展计划 (GAP) 第 4 季:塑造 YGG 的成就版图

基于前三个赛季所取得的成果&#xff0c;Yield Guild Games&#xff08;YGG&#xff09;自豪地宣布推出 公会发展计划&#xff08;GAP&#xff09;第 4 季。公会最近的一些精英成员将在本季加入公会&#xff0c;公会成员将在全新的任务中磨练自己的技能&#xff0c;建立自己在 …

HOT80-划分字母区间

leetcode原题链接&#xff1a;划分字母区间 题目描述 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。返回…

ArcGIS Pro简介下载安装地址

ArcGIS Pro简介 ArcGIS Pro是一款功能强大的地理信息系统&#xff08;GIS&#xff09;软件&#xff0c;由Esri开发。它为用户提供了一种直观、灵活且高效的方式来处理、分析和可视化地理数据。ArcGIS Pro具有现代化的用户界面和工作流程&#xff0c;使用户能够更好地利用地理信…

修改k8s pod的挂载目录

1、找到挂载的服务 kubectl get service2、编辑pod的环境配置 kubectl edit deployment vendor-basic-bill-executor3、找到需要挂载的目录

Kubernetes(K8s)从入门到精通系列之十:使用 kubeadm 创建一个高可用 etcd 集群

Kubernetes K8s从入门到精通系列之十&#xff1a;使用 kubeadm 创建一个高可用 etcd 集群 一、etcd高可用拓扑选项1.堆叠&#xff08;Stacked&#xff09;etcd 拓扑2.外部 etcd 拓扑 二、准备工作三、建立集群1.将 kubelet 配置为 etcd 的服务管理器。2.为 kubeadm 创建配置文件…

【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用(含无目标函数,考虑代理模型)

【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用&#xff08;含无目标函数&#xff0c;考虑代理模型&#xff09; 版本更新&#xff1a; 2023/8/5&#xff1a; 1.因BP作为代理模型不稳定&#xff0c;经过测试&#xff0c;libsvm比rf /bp 效果稳定且精…

MSF恶意程序利用——CS上线

Msfvenom是一个Metasploit独立的有效负载生成器&#xff0c;也是msfpayload和msfencode的替代品。是用来生成后门的软件。 申明&#xff1a;本篇文章的用意仅做学习使用&#xff01; 网络搭建环境&#xff1a; 软件&#xff1a;Vmware Workstation 17 攻击机&#xff1a;Ka…

【手撕C语言】多线程

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言,Linux基础,ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的一句鸡汤&#x1f914;&…

Qt-QSlider样式

文章目录 QSliderQSS 代码QSlider 分析QSlider The slider is the classic widget for controlling a bounded value.It lets the user move a slider handle along a horizontal or vertical groove and translates the handles position into an integer value within the l…