LINUX系统编程-----中

news2024/7/4 6:05:58

文章目录

  • 进程间的通信
    • 管道
      • popen 和 pclose
      • pipe
      • FIFO
    • 共享内存
    • system V 版本的共享内存
      • 创建/获取共享内存
    • 共享内存涉及的函数
      • 共享内存的通信
      • 两个进程同时对共享内存进行读写
    • 信号量
    • 使用信号量保护共享资源
    • 消息队列
    • 死锁
  • 信号
    • 内核不可中断状态

进程间的通信

管道

在操作系统中,管道(Pipe)是一种用于进程间通信的机制。其中有名管道和匿名管道是两种不同类型的管道。

有名管道(Named pipe)也叫FIFO(First In First Out),它是一种存在于文件系统中的特殊文件,可以用于不同进程之间通信。有名管道需要通过mkfifo函数创建,并且必须以某种方式命名,以允许多个进程通过相同的名称打开和使用该管道。有名管道的数据传输是半双工的,即在同一时间只能有一个进程写入数据,而其他进程只能读取数据。

匿名管道(Anonymous pipe)则是一种无需文件系统支持的管道,用于具有父子关系的进程之间进行单向通信。匿名管道由pipe函数创建,其传输方向为单向,只能从一个进程的输出端到另一个进程的输入端。匿名管道的缺点是只能在具有亲缘关系的进程之间使用。

popen 和 pclose

popen()pclose() 是 C 语言标准库中与处理进程相关的两个函数。

popen() 函数可以用于打开一个管道并启动一个进程,返回一个文件指针,可以通过该文件指针来读取或写入被启动进程的标准输入或输出。函数原型如下:

#include <stdio.h>
FILE *popen(const char *command, const char *mode);

command 参数是一个字符串,表示要执行的命令,类似于在终端上输入的命令。mode 参数是一个字符串,指定使用 popen() 打开的管道是读取模式还是写入模式。

popen() 函数成功时返回一个文件指针,失败时返回 NULL

pclose() 函数用于关闭由 popen() 打开的文件流,并结束对应的进程。函数原型如下:

#include <stdio.h>
int pclose(FILE *stream);

stream 参数是由 popen() 返回的文件指针。pclose() 函数返回被结束进程的退出状态码。

需要注意的是,使用 popen()pclose() 函数需要特别小心,因为它们会创建新的进程。如果不谨慎使用,可能会引发安全问题。另外,这两个函数只适用于 Unix-like 系统。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp;
    char buffer[1024];

    fp = popen("ls -l", "r");
    if (fp == NULL) {
        fprintf(stderr, "Failed to run command\n");
        exit(1);
    }

    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }

    pclose(fp);

    return 0;
}

pipe

使用系统调用 pipe 可以创建匿名管道,为了支持可移植性,管道是半双工的,所以一般同时使用两条管道来实现全双工通信。使用 pipe 之前,需要首先创建一个大小为2的整型数组,用于存储文件描述符。但系统调用执行完成之后,pipefd[0]是读端的文件描述符,pipefd[1]是写端的文件描述符。

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    int fds[2];
    if (pipe(fds) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if (pid == 0) { // 子进程
        close(fds[1]); // 关闭子进程写端
        char buf[128] = {0};
        ssize_t nbytes = read(fds[0], buf, sizeof(buf));
        if (nbytes == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }
        printf("%s\n", buf);
        exit(EXIT_SUCCESS);
    }
    else { // 父进程
        close(fds[0]); // 关闭父进程读端
        ssize_t nbytes = write(fds[1], "hello", 5);
        if (nbytes == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }
        wait(NULL); // 等待子进程退出
        exit(EXIT_SUCCESS);
    }
}

FIFO

FIFO(First In First Out)是一种基于文件操作的进程间通信方式,也被称为命名管道。它提供了一个特殊的文件类型,可以在不相关进程之间传递数据。FIFO 在外观上类似于常规的 Unix 管道,但其使用方式有所不同。FIFO 具有一个在文件系统中唯一的路径名,并通过调用 mkfifo 函数进行创建,创建后即可在任意进程中打开和读写。

与普通文件不同的是,FIFO 既可以读也可以写,并且数据遵循先进先出的原则进行读写。当一个进程向 FIFO 中写入数据时,另一个进程可以从 FIFO 中读取这些数据。如果没有进程正在读取 FIFO 中的数据,写入的数据将被存储在 FIFO 中,直到有进程来读取它们。

下面是一个简单的使用 FIFO 进行进程间通信的示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO_NAME "/tmp/my_fifo"

int main() {
    const char *msg = "Hello, FIFO!";
    int fd;
    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 文件权限:rw-r--r--
    if (mkfifo(FIFO_NAME, mode) == -1) { // 创建 FIFO
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for readers...\n");
    fd = open(FIFO_NAME, O_WRONLY); // 打开 FIFO 写端
    printf("Got a reader. Writing data...\n");
    write(fd, msg, sizeof(msg)); // 向 FIFO 中写入数据
    printf("Data written.\n");
    close(fd); // 关闭 FIFO 写端
    exit(EXIT_SUCCESS);
}

在上面的示例中,我们首先定义了一个名为 FIFO_NAME 的常量,它是 FIFO 在文件系统中唯一的路径名。然后使用 mkfifo 函数创建了一个名为 /tmp/my_fifo 的 FIFO,并指定了该文件的权限。

接着,在等待读取者到来时,调用 open 函数打开 FIFO 的写端,并向其中写入数据。最后,关闭 FIFO 的写端并退出程序。

需要注意的是,FIFO 是阻塞的,这意味着当没有任何进程读取 FIFO 中的数据时,写入数据的进程将被阻塞,直到另一个进程来读取数据为止。同样,当没有任何进程向 FIFO 中写入数据时,读取数据的进程也会被阻塞。因此,在实际使用中,我们通常需要使用多线程或异步 I/O 等技术来防止进程被阻塞。

共享内存

共享内存是一种用于在进程之间共享数据的技术。使用共享内存的原因有以下几个方面:

  1. 提高进程间通信效率:相较于其他进程间通信方式(如管道、消息队列等),共享内存具有更高的速度和效率,因为它不需要在进程之间复制数据,而是直接将内存区域映射到多个进程的地址空间中。
  2. 方便数据共享:共享内存可以将同一块内存区域映射到多个进程的地址空间中,在这些进程之间共享数据变得非常简单。这对于需要在多个进程之间协作完成某项任务的应用程序非常有用。
  3. 简化编程逻辑:通过使用共享内存,不必像其他 IPC 机制那样使用繁琐的系统调用来发送和接收数据。这使得编写并发程序变得更加容易。
  4. 节省系统资源:由于共享内存不需要在进程之间复制数据,因此可以节省系统资源,提高系统的整体性能。

需要注意的是,共享内存也存在一些潜在的问题,例如数据同步和互斥、权限控制等方面的问题。如果使用不当,可能会导致数据损坏或程序崩溃等问题。因此,在使用共享内存时,需要仔细考虑和实现相关的同步机制和安全措施。

内存管理单元(MMU)是一种硬件组件,用于在计算机中管理和控制程序访问内存的方式。MMU负责将虚拟内存地址转换为物理内存地址,并确保每个程序只能访问其分配的内存区域,从而防止程序之间的干扰或损坏。

MMU通过利用地址转换技术实现这一功能。当程序尝试访问虚拟内存地址时,MMU会查找页表,将其转换为对应的物理内存地址,然后将数据从物理内存中读取或写入。如果程序尝试访问未分配给它的内存,MMU将拒绝该请求并抛出异常。

除了内存保护外,MMU还可以帮助实现操作系统的虚拟内存管理、进程隔离和安全性。它是现代计算机体系结构中必不可少的组成部分。

system V 版本的共享内存

ftok()函数是一个用于将文件路径名和一个整数标识符(项目 ID)转换为唯一的System V IPC(Inter-Process Communication,进程间通信)键值的函数。它的原型定义在头文件 sys/ipc.h 中:

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

当使用System V IPC进行进程间通信时,往往需要一个唯一的IPC键来标识一个共享的资源(如消息队列、共享内存等)。这个键是由path参数和proj_id参数组合而成的。其中path表示被关联的文件的路径名,proj_id则是用户自定义的单调递增的序号。

ftok()函数通过计算出一个唯一的整数值来返回一个键值(key_t类型),该值可供 System V IPC使用。这个计算过程中,使用了 path 和 proj_id 两个参数,因此只要这两个参数不同,得到的键值就是唯一的。

例如,如果两个进程都需要访问同一块共享内存区域,它们可以通过 ftok 函数得到相同的键值,然后分别调用 shmget 函数来获取对该共享内存区域的引用。

创建/获取共享内存

使用 System V IPC 机制创建和获取共享内存的主要步骤如下:

  1. 调用 ftok 函数生成一个键值(key)。
  2. 调用 shmget 函数创建或获取一个共享内存区域,并返回一个共享内存标识符(shmid)。
  3. 调用 shmat 函数将共享内存附加到当前进程的地址空间中,并返回指向共享内存首地址的指针。
  4. 当不再需要访问共享内存时,调用 shmdt 函数将共享内存从当前进程的地址空间中分离。
  5. 当所有进程都不再使用该共享内存时,调用 shmctl 函数删除共享内存对象。

//创建共享内存
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_SIZE 1024

int main() {
    int shmid;
    key_t key;
    char *shm, *s;

    // 生成键值
    key = ftok(".", 'a');

    // 创建共享内存段
    shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    // 将共享内存连接到当前进程的地址空间
    shm = shmat(shmid, NULL, 0);
    if (shm == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    // 写入数据到共享内存
    s = shm;
    for (char c = 'a'; c <= 'z'; c++) {
        *s++ = c;
    }
    *s = '\0';

    // 分离共享内存
    if (shmdt(shm) == -1) {
        perror("shmdt");
        exit(1);
    }

    printf("共享内存已创建\n");
    return 0;
}

  1. 获取共享内存

要获取一个已经存在的共享内存段,需要执行以下步骤:

  • 使用 ftok 函数生成一个键值。
  • 调用 shmget 函数获取共享内存标识符(shmid)。
  • 调用 shmat 函数将共享内存连接到当前进程的地址空间,并返回指向共享内存段的指针。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    int shmid;
    key_t key;
    char *shm, *s;

    // 生成键值
    key = ftok(".", 'a');

    // 获取共享内存段
    shmid = shmget(key, 0, 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    // 将共享内存连接到当前进程的地址空间
    shm = shmat(shmid, NULL, 0);
    if (shm == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    // 读取共享内存中的数据
    for (s = shm; *s != '\0'; s++) {
        putchar(*s);
    }
    putchar('\n');

    // 分离共享内存
    if (shmdt(shm) == -1) {
        perror("shmdt");
        exit(1);
    }

    printf("共享内存已获取\n");
    return 0;
}

共享内存涉及的函数

共享内存是一种进程间通信的方式,涉及的函数与参数如下:

  1. shmget() 函数:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
  • key:共享内存区域的标识符,通过它来识别同一块共享内存区域。
  • size:共享内存区域的大小,单位是字节。
  • shmflg:标志位,用来指定对共享内存区域的访问权限和操作方式。
  1. shmat() 函数:
#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid:由shmget()函数返回的共享内存区域标识符。
  • shmaddr:指定将共享内存附加到进程地址空间的地址,通常设置为NULL,由系统自动分配一个空闲地址。
  • shmflg:标志位,用于指定共享内存的访问权限和附加方式。
  1. shmdt() 函数:
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);
  • shmaddr:指向共享内存区域的指针,通常是由shmat()函数返回。
  1. shmctl() 函数:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid:共享内存区域的标识符,用于标识要进行操作的共享内存区域。
  • cmd:指定要执行的操作类型,例如IPC_STAT、IPC_SET等。
  • buf:共享内存区域的状态信息结构体,用于获取或者设置共享内存区域的相关信息。

共享内存的通信

共享内存是一种在多个进程之间共享数据的方式,它可以用于进程间通信(IPC),特别适合于需要高速数据传输的场景。共享内存允许多个进程访问同一块物理内存区域,这样就避免了进程之间频繁地进行数据拷贝和通信的开销。

在使用共享内存进行进程间通信时,通常需要以下步骤:

  1. 创建共享内存区域:在Linux系统中,可以使用shmget()函数创建共享内存区域。该函数需要指定共享内存区域的大小、权限等参数,并返回一个共享内存标识符(shmid)。
  2. 将共享内存区域映射到进程地址空间:可以使用shmat()函数将共享内存区域映射到进程的地址空间中。该函数需要指定共享内存标识符和映射的地址位置,返回映射后的地址指针。
  3. 进行数据读写操作:多个进程都可以通过映射后的地址指针访问共享内存区域中的数据,从而实现数据的读写操作。
  4. 解除共享内存区域映射:在不再需要使用共享内存区域时,可以使用shmdt()函数解除共享内存区域的映射关系。
  5. 删除共享内存区域:可以使用shmctl()函数删除共享内存区域。该函数需要指定共享内存标识符和操作类型,通常使用IPC_RMID操作类型来删除共享内存区域。

需要注意的是,在使用共享内存进行进程间通信时,需要对数据访问进行同步控制,以避免多个进程同时修改数据造成的竞争条件。常用的同步控制方式包括信号量、互斥锁等。

两个进程同时对共享内存进行读写

如果两个进程同时对共享内存进行写操作,就有可能导致数据的不一致性。因为这两个进程可能会同时写入相同的内存位置,从而造成数据被覆盖或丢失。

为了避免这种情况,可以使用互斥锁(mutex)来保护共享内存。当一个进程要访问共享内存时,它需要先获得互斥锁。如果另一个进程已经持有了锁,则该进程必须等待直到锁被释放。一旦一个进程拿到了锁,它就可以安全地访问共享内存,并在完成操作后释放锁,以便其他进程可以访问共享内存。

使用互斥锁可以确保每次只有一个进程能够访问共享内存,从而保证数据的一致性。

信号量

信号量(Semaphore)是一种用于控制多个进程/线程互斥访问共享资源的机制。它通常作为进程间同步或线程间同步的手段之一,在操作系统和并发编程中被广泛使用。

在操作系统中,信号量是一个计数器,初始值为一个非负整数。当进程需要获取某个共享资源时,首先检查信号量的值是否大于0,如果大于0,则将信号量的值减1,并允许进程访问该共享资源;如果等于0,则表示该共享资源已被其他进程占用,当前进程需要等待,直到信号量的值变为大于0。当进程释放共享资源时,需要将信号量的值加1,以便其他进程可以继续访问该共享资源。

在并发编程中,信号量通常由一个类实现。在Java语言中,可以使用java.util.concurrent.Semaphore类来实现信号量机制。

信号量是一种用于进程间同步的IPC。信号量本身是一个计数器,表示有多少个共享资源可以共享使用。 当进程访问共享资源时,首先需要需要检查信号量的数值,如果信号量为正,那么进程就可以使用该资 源,并且信号量数值减1,也就是操作系统所述的P操作;如果信号量的数值为0,那么就进程就休眠直 到信号量大于0。当进程不再访问共享资源的时候,信号量加1,并且唤醒休眠的进程,这就是操作系统 所述的V操作。为了在进程切换的时候也能保证信号量的正确性,信号量值的测试和减1操作是原子操 作,也被称为原语,原子这里代表不可分割的含义。如果信号量的值初始为1,那么就可以被称为二元信 号量。

使用信号量保护共享资源

在并发编程中,临界区指的是一段代码或者程序区域,这些代码会访问共享资源(如内存、文件等),而当多个线程同时访问这些资源时,就可能产生竞态条件(race condition)或者其他不确定性的行为。因此,在临界区内部需要采取特殊的措施来保证同步和互斥,以避免多个线程同时对共享资源进行访问,从而导致数据的损坏或者结果的异常。通常可以通过使用锁、信号量、互斥体等同步机制来实现对临界区的保护。

消息队列

消息队列是一种基于异步通信的消息传递机制,它将消息发送者和接收者解耦,并允许它们独立地处理消息。在消息队列中,消息发送者将消息发送到队列中,而消息接收者则从队列中取出消息并进行处理。

消息队列通常由以下几个部分组成:

  1. 消息生产者:负责创建并发布消息到队列中。
  2. 消息队列:存储所有发布的消息,并将其按照指定的规则进行排序和管理。
  3. 消息消费者:从队列中获取消息并对其进行处理。

消息队列有很多优点,包括:

  1. 解耦:消息队列可以将消息发送者和接收者解耦,从而提高系统的可扩展性和灵活性。
  2. 异步:消息队列支持异步通信,可以让发送者和接收者不必等待对方的响应,从而提高系统的响应速度和吞吐量。
  3. 缓冲:消息队列可以作为缓冲区,帮助平衡发送者和接收者之间的数据流量,从而避免系统的瓶颈问题。
  4. 可靠性:消息队列通常具有很高的可靠性,可以通过复制和备份等方式来保证数据的安全性和可用性。
    消息队列通常涉及以下几个函数:

msgget:创建一个新的消息队列或者获取已有的消息队列。

msgsnd:向消息队列中发送一条消息。

msgrcv:从消息队列中接收一条消息。

msgctl:对消息队列进行控制(例如删除消息队列)。

这些函数是用于在进程之间传递数据的,它们可以被用于实现各种不同的应用程序,例如多进程协作、任务分发等。

死锁

死锁是指两个或多个进程在执行过程中,因竞争资源而造成的一种互相等待的现象,若无外力作用,它们都将无法继续执行下去。简单来说,就是一个进程持有某个资源并请求其他进程所持有的资源,但其他进程又不释放该资源,导致所有进程都被阻塞,不能继续执行。

死锁通常发生在多进程并发编程中,比如多线程共享同一资源时,如果对资源的访问没有进行适当的同步和协调,就容易出现死锁。解决死锁的方法包括:避免、预防、检测和恢复。其中,避免死锁是最好的方法,可以通过加锁的顺序、限制资源的使用等方式来避免死锁的发生;预防死锁则需要采取一些特定的策略和算法;检测死锁可以通过系统监控和记录来实现;恢复死锁则需要采取一些紧急措施,比如强制终止进程或者回滚操作等。

信号

在 Linux 中,信号(signal)是一种进程间通信机制,用于向进程发送信息以通知它们发生了某个事件。

Linux 中支持数十种不同的信号,每个信号都有一个唯一的整数标识符。这些信号可以分为两类:

  1. 异步信号:由操作系统或其他进程触发,例如 SIGTERM(终止进程)和 SIGKILL(强制终止进程)等。
  2. 同步信号:由应用程序自身触发,例如 SIGSEGV(段错误)和 SIGFPE(浮点异常)等。

当进程接收到一个信号时,它可以采取以下三种行为之一:

  1. 忽略该信号
  2. 执行默认操作,例如终止进程或者核心转储
  3. 执行用户指定的处理函数

除了 SIGKILL 和 SIGSTOP 信号外,大多数信号都可以被捕获和处理。我们可以通过调用 signal() 或者 sigaction() 函数来为一个进程注册信号处理函数。当该进程接收到对应的信号时,就会执行该处理函数。

需要注意的是,信号处理函数应该尽量简短,因为它们会打断正在执行的代码流程,可能导致数据出错或锁死问题。

signal() 函数可以用于为一个进程注册信号处理函数。它的函数原型如下:

#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int);

该函数接收两个参数:

  1. signum:要注册处理函数的信号编号。
  2. handler:指向信号处理函数的指针。

signal() 函数返回一个指向以前信号处理函数的指针,如果返回值是 SIG_ERR,则表示注册失败。

在使用 signal() 函数时,需要注意以下几点:

  1. 信号处理函数必须具有以下形式:void handler(int sig),其中 sig 是接收到的信号编号。
  2. 如果将 handler 参数设置为 SIG_IGN,则表示忽略该信号。
  3. 如果将 handler 参数设置为 SIG_DFL,则表示执行默认操作。

内核不可中断状态

处于内核不可中断状态(进程控制块的state成员此时为TASK_UNINTERRUPTIBLE)的进程无法接受并 处理信号。处于这种的状态的进程在 ps 中显示为D,通常这种状态出现在进程必须不受干扰地等待或者 等待事件很快会发生的时候出现,比如进程正在等待磁盘读写数据的时候。对于非嵌入式程序员而言, 这种状态是几乎没办法实现。内核不可中断状态是进程等待态的一种形式。

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

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

相关文章

【备战秋招】每日一题:4月1日美团春招(二批)第三题:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站&#xff08;含题解&#xff09; www.codefun2000.com 最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据&#xff0c;挂载到我们的OJ上&#xff0c;供大家学习交流&#xff0c;体会笔试难度。现已录入200道互联网大厂模拟练习题&…

Electron简单开发

文章目录 1.参考网站2.HelloWold编写2.1新建空文件夹2.2node初始化2.3安装electron依赖2.4添加.gitignore 文件2.5创建main.js文件和index.html2.6运行electron应用 3.打包 接到一个任务&#xff0c;将electron集成到solidworks中&#xff0c;所以记录一下electron的简单操作&a…

【操作系统】05.文件管理

文件管理 文件的属性 文件内部数据的组织 文件之间的组织 操作系统向上层提供功能 创建文件 删除文件 打开文件 关闭文件 读文件 写文件 文件的逻辑结构 无结构文件 有结构文件 顺序文件 文件的物理结构 磁盘块&#xff08;文件块&#xff09; 连续分配 优点 对于机…

操作系统 四、文件管理

文章目录 4.1 文件的逻辑结构4.2 文件目录4.2.1 目录结构4.2.1.1 单级目录结构4.2.1.2 两级目录结构4.2.1.3 多级目录结构4.2.1.4 无环图目录结构 4.2.2 索引结点(FCB的改进) 4.3 文件的物理结构4.3.1 连续分配4.3.2 链接分配4.3.2.1 隐式链接4.3.2.2 显式链接 4.3.3 索引分配 …

稠密点云获取方法(二)

作为高分辨率三维重建的方法之一,从单张图像生成稠密三维点云在计算机视觉领域中一直有着较高的关注度。 以下文献提出了一种针对二维和三维信息融合的方法以解决三维点云稀疏难以检测远处的目标的问题。 Multimodal Virtual Point 3D Detection 该文献提出一种将 RGB 传感器…

【Mysql】| 超详细常见bug及解决方案

目录 一. &#x1f31f; 引入话题二. &#x1f31f; 引出bug1.1 查看bug1.2 Problem Solving2.1 查看bug2.2 Problem Solving3.1 字段长度异常3.2 Problem Solving 三. &#x1f31f; 最后 一. &#x1f31f; 引入话题 MySQL是一款广泛使用的开源数据库管理系统&#xff0c;它…

小白了解Docker容器技术

一、什么是Docker&#x1f451; 有一个最常见的例子来很好的帮我们简单了解Docker容器技术&#xff1a; 当我们在一台计算机中配置好了环境&#xff0c;花费了极大的时间和精力成功开发部署好了一个应用。准备尝试在不同操作系统、不同环境下部署这个应用时&#xff0c;我们需要…

图及其与图相关的算法

⭐️前言⭐️ 本篇文章主要介绍图及其与图相关的算法 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 &#x1f349;博客中涉及源码及博主…

如何在 Rocky Linux 上检查磁盘空间?

在 Rocky Linux 上检查磁盘空间是系统管理和维护的重要任务之一。磁盘空间的监控和管理可以帮助我们及时发现和解决存储空间不足的问题&#xff0c;以确保系统的正常运行。本文将详细介绍在 Rocky Linux 上检查磁盘空间的方法。 方法 1&#xff1a;使用 df 命令 df 命令是 Li…

SOLIDWORKS技巧大全培训教程

1 您可以使用 CTRLTAB 键循环进入在 SolidWorks 中打开的文件。 2 使用方向键可以旋转模型。按 CTRL 键加上方向键可以移动模型。按 ALT 键加上方向键可以将模型沿顺时针或逆时1 您可以使用 CTRLTAB 键循环进入在 SolidWorks 中打开的文件。 2 使用方向键可以旋转模型。按 CTRL…

【CloudCompare教程】012:基于点云数据的测量功能

本文讲解CloudCompare基于点云数据的测量功能,主要有:点云索引、坐标、距离、角度、面积、标签等。 文章目录 一、加载地形点云数据二、基于点云数据的测量功能1. 选择单点并显示信息2. 选择两点并显示分割信息3. 选择三点并显示相关三角形信息4. 定义矩形2D标签5. 保存当前标…

Milvus向量数据库

Milvus vector database 第一章 Milvus概述 Milvus创建于2019年&#xff0c;唯一的目标是&#xff1a;存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的大量嵌入向量embedding vectors。 存储对象&#xff1a;向量 NOTE&#xff1a;embedding vectors是对非结构…

c#快速入门(下)

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;Inline和lambda委托和lambda &#x1f449;&#x1f…

上海斯歌荣获中国低代码/零代码行业“卓越影响力厂商奖”

3月19日&#xff0c;在「第三届中国 ISIG 产业智能大会」隆重的颁奖典礼上&#xff0c;上海斯歌被授予“卓越影响力厂商奖”&#xff0c;并入围国内权威咨询机构LowCode低码时代的《2022年中国低代码&零代码行业研究报告》卓越影响力榜单。 「第三届ISIG中国产业智能大会」…

如何编写接口自动化框架系列通过yaml来管理测试用例(四)

本文是接口自动化测试框架系列篇的第四篇 &#xff0c;主要介绍yaml包的使用 。自动化测试的本质是将功能测试用例交给代码去 目录 1. yaml介绍&#xff1f; 2.python中的yaml包 3.项目中使用yaml包 4 项目总结 执行 &#xff0c;测试人员往往是在自动化框架添加对应的测试…

惠普83752B高功率合成扫频器,20 GHz

惠普83752B扫频仪为元器件测试市场带来了卓越的综合性能&#xff0c;在通用台式扫频仪、扫频仪或标量测试应用中&#xff0c;83752B提供了性价比最高的性能。这款扫频仪在保持模拟源速度的同时&#xff0c;提供了卓越的精度和稳定性。全合成CW、步进和科坡扫描模式可在宽带和窄…

QT+OpenGL几何着色器

QTOpenGL几何着色器 本篇完整工程见gitee:QtOpenGL 对应点的tag&#xff0c;由turbolove提供技术支持&#xff0c;您可以关注博主或者私信博主 几何着色器 几何着色器的输入是一个图元&#xff08;如点或者三角形&#xff09;的一组顶点几何着色器可以再顶点发送到下一着色器…

Linux——进程的等待

目录 前言&#xff1a; 一.进程等待 父进程回收子进程信息的相关函数1&#xff1a;wait函数 实验案例1&#xff1a;设置wait函数参数为NULL 实验案例2&#xff1a;wait函数带wstatus参数的案例&#xff1a;当子进程正常运行完退出时 情况3&#xff1a; wait函数带wstatus参数…

Softing“物联网连接和OPC UA通信”系列研讨会

— 免费线上研讨会概览 — 您是否正在为车间应用寻找机器连接&#xff1f;您是否需要为创新的物联网解决方案制定架构决策&#xff1f;或者您是否已经选择了物联网平台&#xff0c;需要连接组件来访问自动化网络中的数据&#xff1f;在Softing线上研讨会中&#xff0c;我们将讨…

JavaScript 进阶 (三)

目录 编程思想 面向过程编程 面向对象编程 构造函数 原型 原型 constructor 属性 对象原型 原型继承 原型链 编程思想 面向过程编程 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候再一个一个的依次 调用…