【并发程序设计】15.信号灯(信号量)

15.信号灯(信号量)

Linux中的信号灯即信号量是一种用于进程间同步或互斥的机制,它主要用于控制对共享资源的访问。

在Linux系统中,信号灯作为一种进程间通信(IPC)的方式,与其他如管道、FIFO或共享内存等IPC方式不同,信号灯主要用于同步或互斥控制,以确保多个进程之间能够协调地访问共享资源。信号灯可以看作是内存中的一个标志,进程可以通过检查信号灯的状态来决定是否可以安全地访问某些共享资源

要点

  1. 创建和操作:要在Linux中使用信号灯,首先需要创建一个信号灯,并指定其初始值。对于二值信号灯,这个初始值通常是1,表示资源一开始是可用的。
  2. 等待和释放:进程可以执行等待操作来测试信号灯的值,如果信号灯的值大于0,则进程可以继续执行并将信号灯的值减1;如果值为0,则进程必须等待直到信号灯的值变为正数。
  3. 共享资源控制:信号灯提供了一种机制,使得进程能够根据信号灯的状态来判断是否可以访问某些共享资源。这类似于互斥锁,确保了在任何时候只有一个进程可以访问临界区。
  4. 进程间通信:除了同步和互斥,信号灯还可以作为进程间通信的一种方式。它们存在于内核空间,与共享内存和消息队列一起构成了Linux中主要的IPC通信方式。
  5. 有名信号灯: 可以通过路径名在进程间共享,因此不同进程可以通过已知的路径名来访问同一个有名信号灯。 适用于需要在不同进程间进行同步的场景。
  6. 无名信号灯: 只能存在于内存中,因此使用无名信号灯的进程必须能够访问相同的内存区域。通过共享内存的方式创建,不依赖于文件系统中的路径名。适用于单进程内多线程间的同步或在已经映射相同内存内容的多个进程之间的同步。
  7. System V信号灯:Linux支持System V的信号灯,这是一种传统的信号灯实现,用于在同一系统内的进程间进行同步和互斥。

互斥和同步 是信号灯通常用于解决并发中的两个主要问题:

  1. 互斥:确保当一个进程使用共享资源时,其他进程不能同时访问该资源。例如,打印设备只能由一个进程使用,其他尝试访问打印设备的进程必须等待,直到当前进程完成打印任务。

  2. 同步:确保进程间的执行顺序符合特定的依赖关系。例如,一个进程生成数据,另一个进程消费这些数据,消费者进程需要等待生产者进程生成数据后才能继续执行。

PV操作

信号灯的工作原理基于PV操作,其中P操作用于请求资源(减少信号量的值),而V操作用于释放资源(增加信号量的值)。

  • P操作“proberen”(尝试):如果信号量的值为正,则将其减一,允许进程继续执行。如果信号量的值为0或负,则进程被阻塞,直到信号量的值变为正数。

  • V操作“verhogen”(释放):将信号量的值加一,如果有其他进程因等待该信号量而被阻塞,则其中一个进程会被唤醒。

POSIX是一组用于确保操作系统间可移植性的IEEE标准,主要针对Unix系统。POSIX标准为操作系统提供了一套共通的规则,使得软件开发更加高效,同时也让用户能够在不同的系统之间无缝地迁移和运行应用程序。

有名信号灯

用到的函数主要有:

  1. sem_open 有名信号灯打开
  2. sem_close 有名信号灯关闭
  3. sem_unlink 有名信号灯的删除
  4. sem_wait 信号灯P操作,申请资源
  5. sem_post 信号灯V操作,释放资源

sem_open 函数

  1. 原型

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <semaphore.h>
    sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
    
  2. 功能:创建或打开一个有名信号量(named semaphore)的函数

  3. 参数

    • name:信号量的名称,用于标识信号量。
    • oflag:打开选项,可以是以下值的组合:
      • O_CREAT:如果信号量不存在,则创建一个新的信号量。
      • O_EXCL:与O_CREAT一起使用,表示如果信号量已存在,则返回错误。
      • O_RDWR:允许对信号量进行读写操作。
    • mode:设置信号量的权限,通常设置为0644。
    • value:信号量的初始值。
  4. 返回值

    • 成功时,返回一个指向信号量的指针。
    • 失败时,返回SEM_FAILURE(通常是NULL)。

sem_close 函数

  1. 原型

    #include <semaphore.h>
    int sem_close(sem_t *sem);
    
  2. 功能:用于关闭一个信号量的函数

  3. 参数

    • sem:指向要关闭的信号量的指针
  4. 返回值

    • 成功时,返回0。
    • 失败时,返回-1,并设置errno。

sem_unlink 函数

  1. 原型

    #include <semaphore.h>
    int sem_unlink(const char *name);
    
  2. 功能:删除一个命名信号量

  3. 参数

    • name:要删除的信号量的名称
  4. 返回值

    • 成功时,返回0
    • 失败时,返回-1,并设置errno

sem_wait 函数

  1. 原型

    #include <semaphore.h>
    int sem_wait(sem_t *sem);
    
  2. 功能:”P操作“等待一个信号量。当信号量的值大于0时,该函数会将信号量的值减1,并立即返回。如果信号量的值为0,则该函数会阻塞当前线程,直到信号量的值大于0为止。

  3. 参数

    • sem:指向要等待的信号量的指针。
  4. 返回值

    • 成功时,返回0。
    • 失败时,返回-1,并设置errno。

sem_post 函数

  1. 原型

    #include <semaphore.h>
    int sem_post(sem_t *sem);
    
  2. 功能:”V操作“增加一个信号量的值。当信号量的值大于0时,如果有其他线程正在等待该信号量,则sem_post函数会唤醒其中一个等待的线程。如果没有线程在等待,那么信号量的值简单地增加,它与sem_wait函数相对应.

  3. 参数

    • sem:指向要操作的信号量的指针。
  4. 返回值

    • 成功时,返回0。
    • 失败时,返回-1,并设置errno。

示例-有名信号灯使用

使用信号量和共享内存实现的简单进程间通信(IPC)示例

一个简单的命令行界面,用户可以在命令行中输入字符串,并将其存储到共享内存中。通过信号量来实现进程间的同步,确保数据的读写操作不会发生冲突

tes_semw.c 写程序

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>void delsemfile(int sig)
{
sem_unlink("mysem_w");  // 删除名为"mysem_w"的信号量
exit(0);                // 退出程序
}int main()
{
sem_t *sem_r,*sem_w;     // 定义两个信号量指针,分别用于读和写操作
key_t key;               // 定义键值,用于生成共享内存标识符
int shmid;               // 定义共享内存标识符
char *shmaddr;           // 定义共享内存地址指针struct sigaction act;    // 定义信号处理结构体
act.sa_handler = delsemfile;  // 设置信号处理函数为delsemfile
act.sa_flags = 0;        // 设置信号处理标志为0
sigemptyset(&act.sa_mask);   // 清空信号集sigaction(SIGINT,&act,NULL); // 注册信号处理函数,当接收到SIGINT信号时调用delsemfile函数key = ftok(".",100);      // 生成键值,用于创建共享内存标识符
if(key<0)
{perror("ftok");      // 如果生成失败,打印错误信息return 0;            
}shmid = shmget(key,500,0666|IPC_CREAT);  // 创建共享内存段,大小为500字节,权限为0666,如果不存在则创建
if(shmid<0)
{perror("shmget");    // 如果创建失败,打印错误信息return 0;           
}shmaddr = shmat(shmid,NULL,0);  // 将共享内存段附加到进程的地址空间,并获取共享内存地址指针sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);  // 创建名为"mysem_r"的信号量,初始值为0
sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);  // 创建名为"mysem_w"的信号量,初始值为1while(1)
{sem_wait(sem_w);    // 等待名为"mysem_w"的信号量变为非零值printf(">");        // 输出提示符">"fgets(shmaddr,500,stdin);  // 从标准输入读取一行字符串,存储到共享内存中sem_post(sem_r);    // 增加名为"mysem_r"的信号量的值,表示数据已写入共享内存
}
}

tes_semr.c 读程序

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>void delsemfile(int sig)
{
sem_unlink("mysem_r");  // 删除名为"mysem_r"的信号量
exit(0);                // 退出程序
}int main(){sem_t *sem_r,*sem_w;     // 定义两个信号量指针,分别用于读和写操作
key_t key;               // 定义键值,用于生成共享内存标识符
int shmid;               // 定义共享内存标识符
char *shmaddr;           // 定义共享内存地址指针
struct sigaction act;    // 定义信号处理结构体
act.sa_handler = delsemfile;  // 设置信号处理函数为delsemfile
act.sa_flags = 0;        // 设置信号处理标志为0
sigemptyset(&act.sa_mask);   // 清空信号集sigaction(SIGINT,&act,NULL); // 注册信号处理函数,当接收到SIGINT信号时调用delsemfile函数key = ftok(".",100);      // 生成键值,用于创建共享内存标识符
if(key<0)
{perror("ftok");      // 如果生成失败,打印错误信息return 0;            
}shmid = shmget(key,500,0666|IPC_CREAT);  // 创建共享内存段,大小为500字节,权限为0666,如果不存在则创建
if(shmid<0)
{perror("shmget");    // 如果创建失败,打印错误信息return 0;            
}shmaddr = shmat(shmid,NULL,0);  // 将共享内存段附加到进程的地址空间,并获取共享内存地址指针sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);  // 创建名为"mysem_r"的信号量,初始值为0
sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);  // 创建名为"mysem_w"的信号量,初始值为1while(1)
{sem_wait(sem_r);    // 等待名为"mysem_r"的信号量变为非零值printf("%s\n",shmaddr);  // 输出共享内存中的字符串sem_post(sem_w);    // 增加名为"mysem_w"的信号量的值,表示数据已读取完成
}
}

在这里插入图片描述

运行效果如图,实现了两个进程通讯

可以通过命令ls /dev/shm查看信号量文件;在Linux系统中,/dev/shm目录是用于存放共享内存和信号量文件的特殊目录

ctrl + c退出程序后,捕获到SIGINT信号后执行delsemfile()删除信号量文件

无名信号灯

用到的函数有:

  1. sem_init 初始化无名信号量
  2. sem_destory 销毁无名信号量
  3. sem_wait 信号灯P操作,申请资源
  4. sem_post 信号灯V操作,释放资源

sem_init 函数

  1. 原型

    #include <semaphore.h>
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    
  2. 功能:初始化一个无名信号量

  3. 参数

    • sem:指向要初始化的信号量的指针。
    • pshared:指定信号量的类型,如果为0,则表示该信号量是进程私有的;如果为非0值,则表示该信号量是进程间共享的。
    • value:指定信号量的初始值。
  4. 返回值

    • 成功时,返回0;
    • 失败时,返回-1,并设置errno

sem_destory 函数

  1. 原型

    #include <semaphore.h>
    int sem_destroy(sem_t *sem);
    
  2. 功能:销毁一个无名信号量

  3. 参数

    • sem:指向要销毁的信号量的指针。
  4. 返回值

    • 成功时,返回0;
    • 失败时,返回-1,并设置errno
  5. 注意:只有当信号量的引用计数变为0时,才能安全地销毁它。如果还有其他线程或进程正在等待该信号量,那么销毁操作将失败,并且errno将被设置为EBUSY。在这种情况下,需要确保所有使用该信号量的线程或进程都已经结束,然后再尝试销毁它。

示例-无名信号灯使用

使用信号量和共享内存实现的简单进程间通信(IPC)示例。主要功能是在一个进程中输入字符串,另一个进程中读取并打印这些字符串。

#include <fcntl.h>
#include <sys/stat.h> 
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <pthread.h>sem_t sem_r,sem_w; // 定义两个信号量,用于读写同步
char *shmaddr; // 共享内存地址指针void destroysem(int sig) // 信号处理函数,用于销毁信号量并退出程序
{
sem_destroy(&sem_r); // 销毁读信号量
sem_destroy(&sem_w); // 销毁写信号量
exit(0); // 退出程序
}void *readmem(void *arg) // 读取共享内存中的字符串并打印的线程函数
{
while(1)
{sem_wait(&sem_r); // 等待读信号量printf("%s\n",shmaddr); // 打印共享内存中的字符串sem_post(&sem_w); // 释放写信号量
}
}int main()
{
key_t key; // 键值
int shmid; // 共享内存标识符struct sigaction act; // 信号处理结构体
act.sa_handler = destroysem; // 设置信号处理函数
act.sa_flags = 0; // 设置信号处理标志
sigemptyset(&act.sa_mask); // 清空信号集sigaction(SIGINT,&act,NULL); // 注册信号处理函数key = ftok(".",100); // 生成键值
if(key<0)
{perror("ftok"); // 输出错误信息return 0;
}shmid = shmget(key,500,0666|IPC_CREAT); // 创建共享内存
if(shmid<0)
{perror("shmget"); // 输出错误信息return 0;
}shmaddr = shmat(shmid,NULL,0); // 将共享内存映射到进程地址空间sem_init(&sem_r,0,0); // 初始化读信号量,初始值为0
sem_init(&sem_w,0,1); // 初始化写信号量,初始值为1pthread_t tid; // 线程标识符
pthread_create(&tid,NULL,readmem,NULL); // 创建线程,执行readmem函数while(1)
{sem_wait(&sem_w); // 等待写信号量printf(">"); // 提示用户输入fgets(shmaddr,500,stdin); // 从标准输入读取字符串并存储到共享内存中sem_post(&sem_r); // 释放读信号量
}
}

在这里插入图片描述

运行效果如图

在父进程中,它循环接收用户输入的数据并将其写入共享内存中。在子进程中,它循环读取共享内存中的数据并打印出来。

System V 信号灯

System V 信号灯是一种用于进程间同步和互斥的机制,它允许多个进程共享资源而不会产生冲突。

  1. 信号灯集合:System V 信号灯可以是一个或多个计数信号灯的集合。这意味着可以同时操作集合中的任意多个信号灯,以协调进程间的访问顺序。
  2. 信号灯操作:System V 信号灯的操作通常涉及三个步骤:初始化(创建)、P 操作(等待资源)和 V 操作(释放资源)。P 操作用于请求资源,如果资源不可用则进程将等待;V 操作用于释放资源,使得其他等待该资源的进程可以继续执行
  3. 避免死锁:通过申请多个资源时使用 System V 信号灯,可以减少死锁的风险。死锁是指两个或多个进程在互相等待对方释放资源时无法继续执行的状态。

System V 信号灯是一种重要的同步机制,它在多进程编程中扮演着关键角色,确保了资源的有序访问和数据的一致性。

用到的函数有:

  1. semget 创建/打开信号灯
  2. semop 对信号灯集合中的信号量进行P - V操作
  3. semctl 信号灯集合的控制(初始化/删除)

semget 函数

  1. 原型

    #include <sys/sem.h>
    int semget(key_t key, int nsems, int semflg);
    
  2. 功能:获取一个信号量集的标识符

  3. 参数

    • key:是一个键值,用于唯一标识一个信号量集。通常使用ftok()函数生成。
    • nsems:指定需要创建或获取的信号量数量。
    • semflg:设置信号量集的访问权限和创建标志。可以是以下值的组合:
      • IPC_CREAT:如果信号量集不存在,则创建一个新的信号量集。
      • IPC_EXCL:与IPC_CREAT一起使用,表示如果信号量集已经存在,则返回错误。
      • 0:表示不设置任何特殊标志。
  4. 返回值

    • 如果成功,返回信号量集的标识符(非负整数)。
    • 如果失败,返回-1,并设置errno为相应的错误码。

semop 函数

  1. 原型

    #include <sys/sem.h>
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    
  2. 功能:改变信号量的值,对信号灯集合中的信号量进行P - V操作

  3. 参数

    • semid:是一个信号量集的标识符,由semget()函数返回。
    • sops:是一个指向struct sembuf结构体数组的指针,该数组定义了要执行的操作。
    • nsops:指定sops数组中操作的数量。

    struct sembuf结构体:

    struct sembuf {unsigned short sem_num;  // 信号量编号short sem_op;            // 操作类型short sem_flg;           // 操作标志
    };
    

    各个字段的含义如下:

    • sem_num:指定要操作的信号量的编号。如果设置为0,则表示对整个信号量集进行操作。
    • sem_op:指定要对信号量执行的操作类型。
      • sem_op> 0,它表示进程释放控制的资源,即信号量的值将增加sem_op的数量。
      • sem_op= 0,如果没有设置IPC_NOWAIT标志,调用进程将进入睡眠状态直到信号量的值为0;如果设置了该标志且信号量值不为0,则进程不会进入睡眠,而是直接返回EAGAIN。
      • sem_op< 0,它表示尝试获取资源使用权,信号量的值将增加sem_op的绝对值。如果此时信号量的值小于或等于sem_op的绝对值,操作将会阻塞,直到信号量的值大于或等于sem_op的绝对值。
    • sem_flg:指定操作的标志。可以是以下值的组合:
      • IPC_NOWAIT:非阻塞模式,如果无法立即执行操作,则立即返回。
      • SEM_UNDO:撤销之前的操作。
      • 0:不设置任何特殊标志。
  4. 返回值

    • 如果成功,返回0。
    • 如果失败,返回-1,并设置errno为相应的错误码。

semctl 函数

  1. 原型

    #include <sys/sem.h>
    int semctl(int semid, int semnum, int cmd, ...);
    
  2. 功能:控制信号量集

  3. 参数

    • semid:是一个信号量集的标识符,由semget()函数返回。
    • semnum:指定要操作的信号量的编号。如果设置为0,则表示对整个信号量集进行操作。
    • cmd:指定要执行的命令。可以是以下值之一:
      • IPC_RMID:删除信号量集。(常用)
      • IPC_SET:设置信号量集的属性。(常用)
      • IPC_STAT:获取信号量集的状态信息。(常用)
      • SETVAL:设置信号灯的值,需要用到第四个参数:共用体。(常用)
      • IPC_INFO:获取系统支持的信号量集的最大数量和当前使用的数量。
      • SEM_STAT:获取指定信号量的状态信息。
      • GETALL:获取所有信号量的值。
      • GETNCNT:获取等待某个信号量变为非零值的进程数。
      • GETPID:获取最后一个操作指定信号量的进程ID。
      • GETVAL:获取指定信号量的值。
      • GETZCNT:获取等待某个信号量变为零值的进程数。
      • SETALL:设置所有信号量的值。
    • ...:根据cmd的不同,可能需要传递额外的参数。
  4. 返回值

    • 如果成功,返回相应的结果或状态信息。
    • 如果失败,返回-1,并设置errno为相应的错误码

示例-System V信号灯使用

基于信号量和共享内存的进程间通信(IPC)示例。它创建了一个父子进程,并使用信号量和共享内存进行数据传递。

#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>#define SEM_READ   0
#define SEM_WRITE  1//semctl函数用到的参数
union semun {
int val;
};               // P操作函数,用于对信号量进行减一操作
void Poperation(int semid,int semindex)
{
struct sembuf sbuf;
sbuf.sem_num =  semindex;
sbuf.sem_op = -1;
sbuf.sem_flg = 0;semop(semid,&sbuf,1);
}// V操作函数,用于对信号量进行加一操作
void Voperation(int semid,int semindex)
{
struct sembuf sbuf;
sbuf.sem_num =  semindex;
sbuf.sem_op = 1;
sbuf.sem_flg = 0;semop(semid,&sbuf,1);
}int main()
{
key_t key; // 定义键值key
char *shmaddr; // 共享内存地址指针
int semid,shmid; // 信号量和共享内存的ID
key = ftok(".",100); // 生成键值
if(key<0)
{perror("ftok"); // 如果生成失败,输出错误信息return 0;
}semid = semget(key,2,IPC_CREAT |0666); // 创建信号量集合
if(semid<0)
{perror("semget"); // 如果创建失败,输出错误信息return 0;
}
shmid = shmget(key,500,IPC_CREAT |0666); // 创建共享内存
shmaddr = shmat(shmid,NULL,0); // 将共享内存映射到进程地址空间
union semun mysem; // 定义信号量联合体
mysem.val = 0; // 初始化读信号量的值为0
semctl(semid,SEM_READ,SETVAL,mysem); // 设置读信号量的值
mysem.val = 1; // 初始化写信号量的值为1
semctl(semid,SEM_WRITE,SETVAL,mysem); // 设置写信号量的值pid_t pid; // 定义进程ID
pid = fork(); // 创建子进程
if(pid<0)
{perror("fork"); // 如果创建失败,输出错误信息shmctl(shmid,IPC_RMID,NULL); // 删除共享内存semctl(semid,0,IPC_RMID); // 删除信号量集合exit(-1);
}else if(pid == 0)
{// 子进程循环读取共享内存中的数据并打印while(1){Poperation(semid,SEM_READ); // 对读信号量进行P操作printf("%s\n",shmaddr); // 打印共享内存中的数据Voperation(semid,SEM_WRITE); // 对写信号量进行V操作}
}
else
{// 父进程循环接收用户输入的数据并写入共享内存while(1){Poperation(semid,SEM_WRITE); // 对写信号量进行P操作printf(">"); // 提示用户输入数据fgets(shmaddr,32,stdin); // 从标准输入读取数据并写入共享内存Voperation(semid,SEM_READ); // 对读信号量进行V操作}
}
}

在这里插入图片描述

运行结果如图

在父进程中,它循环接收用户输入的数据并将其写入共享内存中。在子进程中,它循环读取共享内存中的数据并打印出来。

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

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

相关文章

Python保存为json中文Unicode乱码解决json.dump()

保存为json中文Unicode乱码&#xff1a; 可以看到&#xff0c;中文字符没有乱码&#xff0c;只是出现了反斜杠&#xff0c;此时解决方法应考虑是否进行了二次序列化。 一、原因1 在dump时加入ensure_asciiFalse 即可解决&#xff0c;即json.dump(json_data, f, indent4, en…

【Spring-01】BeanFactory和ApplicationContext

【Spring-01】BeanFactory和ApplicationContext 1. 容器接口1.1 什么是 BeanFactory1.2 BeanFactory 能做什么&#xff1f; 1. 容器接口 以 SpringBoot 的启动类为例&#xff1a; /*** BeanFactory 与 ApplicationContext的区别*/ SpringBootApplication public class Spring…

【自动驾驶】针对低速无人车的线控底盘技术

目录 术语定义 一般要求 操纵装置 防护等级 识别代号 技术要求 通过性要求 直线行驶稳定性 环境适应性要求 功能安全要求 信息安全要求 故障处理要求 通信接口 在线升级(OTA) 线控驱动 动力性能 驱动控制响应能力 线控制动 行车制动 制动响应能力 线控转向 总体要求 线控…

STM32作业实现(五)温湿度传感器dht11

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

UML静态图-类图

概述 静态图包含类图、对象图和包图的主要目的是在系统详细设计阶段&#xff0c;帮助系统设计人员以一种可视化的方式来理解系统的内部结构和代码结构&#xff0c;包括类的细节、类的属性和操作、类的依赖关系和调用关系、类的包和包的依赖关系。 一、类图的表示法 类图(Cla…

2024系统架构师软考考题考点回忆版

2024年5月25日系统架构师软考试题/考点梳理 选择题 (75道单选题) 软件测试(P205) 静态测试:是被测程序不运行,只依靠分析和检查源程序的语句、结构、过程来检查程序是否有错误。动态测试:运行被测试程序,对得到的结果与预期的结果进行比较分析,同时分析运行效率和健壮…

(1) 初识QT5

文章目录 Qt Quickdemo信号的命名方式 qml语言一个很重要的概念 qt 模块 Qt Quick Qt Quick是Qt5中⽤户界⾯技术的涵盖。Qt Quick⾃⾝包含了以下⼏种技术&#xff1a; QML-使⽤于⽤户界⾯的标识语⾔JavaScript-动态脚本语⾔Qt C具有⾼度可移植性的C库. 类似HTML语⾔&#xf…

Docker(Centos7+)

先确定是否 Centos 7 及以上的版本 查看是否 ping 通外网 linux centos7运行下面的代码&#xff0c;基本上都可以正常安装 # 删除之前的docker残留 yum -y remove docker*yum install -y yum-utilsyum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/…

Docker最新超详细版教程通俗易懂

文章目录 一、Docker 概述1. Docker 为什么出现2. Docker 的历史3. Docker 能做什么 二、Docker 安装1. Docker 的基本组成2. 安装 Docker3. 阿里云镜像加速4. 回顾 hello-world 流程5. 底层原理 三、Docker 的常用命令1. 帮助命令2. 镜像命令dokcer imagesdocker searchdocker…

反向配置教程

注意&#xff0c;Openai、Gemini、claude和pika接口在国内直连不通&#xff0c;都需要配置反向 一、配置openai反向 1、在海外宝塔添加反向 将海外宝塔升级到最新 在海外宝塔添加一个新站点&#xff08;可以解析一个域名来用&#xff0c;也可以用ip端口形式&#xff09; 打开…

全国水系数据(更新到2024年5月)

上海市水系数据地图可视化 水系数据线图层&#xff08;小河/溪流、江/河、运河、下水道/排水管&#xff09; 水系数据面数据&#xff08;水域、水库、河岸、湿地&#xff09; 水系数据字段说明 可视化预览 北京市水系可视化 上海市水系可视化 广州市水系可视化 深圳市水系可视化…

部署Envoy

Envoy常用术语 envoy文档官网 Life of a Request — envoy 1.31.0-dev-e543e1 documentationhttps://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request#terminology 基础总结 &#xff08;1&#xff09;Envoy Envoy自己本身是工作在L7层的一个proxy&#xff…

如何让大模型更聪明?

【导读】 6月20日下午&#xff0c;163期文汇讲堂“数字强国”系列启动&#xff0c;首期《AIGC驱动生产力跃升与良好世界塑造》&#xff0c;在涌动着毕业季青春气息的华东师大樱桃河畔成功举办。北京智源人工智能研究院副院长兼总工程师林咏华应邀作主讲&#xff0c;华东师大学者…

Whisper-AT:抗噪语音识别模型(Whisper)实现通用音频事件标记(Audio Tagger)

本文介绍一个统一音频标记&#xff08;Audio Tagger&#xff09;和语音识别&#xff08;ASR&#xff09;的模型&#xff1a;Whisper-AT&#xff0c;通过冻结Whisper的主干&#xff0c;并在其之上训练一个轻量级的音频标记模型。Whisper-AT在额外计算成本不到1%的情况下&#xf…

第三届大湾区算力大会丨暴雨开启数字未来新篇

5月30-31日&#xff0c;韶关市迎来主题为“算启新篇智创未来”的第三届粤港澳大湾区(广东)算力产业大会暨第二届中国算力网大会&#xff0c;活动由广东省人民政府主办&#xff0c;广东省政数局、韶关市人民政府共同承办。暴雨信息作为算力产业发展的重要构建者受邀赴会&#xf…

vue-2

vue-cli的安装 vue-cli是一个脚手架工具&#xff0c;它集成了诸多前端技术&#xff0c;包括但不仅限于&#xff1a; webpack、 babel、eslint、http-proxy-middleware、typescript、css pre-prosessor、css module、… 这些工具&#xff0c;他们大部分都要依赖两个东西&…

用例篇03

正交表 因素&#xff1a;存在的条件 水平&#xff1a;因素的取值 最简单的正交表&#xff1a;L4(2) 应用 allpairs 来实现正交表。 步骤&#xff1a; 1.根据需求找出因素和水平 2.将因素和水平写入到excel表格中&#xff08;表格不需要保存&#xff09;&#xff08;推荐用…

WP All Import插件

使用 WP All Imports 插件并将亚马逊产品集成到 WooCommerce 网站中。在您的网站上&#xff0c;他们可以添加到购物车...然后一旦他们按下结帐&#xff0c;他们就会被发送到亚马逊进行付款 WP All Import 是一个强大的WordPress插件&#xff0c;它允许用户从XML或CSV文件中导入…

区块链--Ubuntu上搭建以太坊私有链

1、搭建私链所需环境 操作系统&#xff1a;ubuntu16.04&#xff0c;开虚拟机的话要至少4G&#xff0c;否则会影响测试挖矿时的速度 软件&#xff1a; geth客户端 Mist和Ethereum Wallet&#xff1a;Releases ethereum/mist GitHub 2、安装geth客户端 sudo apt-get update …

day20

第一题 23. 合并 K 个升序链表 本题是已经知道有多个链表&#xff0c;需要我们将这些链表按照升序排列的规则组合到一起&#xff0c;同时这些链表都是升序排列的&#xff1b; 解法一&#xff1a; 利用优先级队列 步骤一&#xff1a;利用优先级队列床架一个小根堆&#xff1b; …