Linux多进程和多线程(一)-进程的概念和创建

  • 进程
    • 进程的概念
    • 进程的特点如下
    • 进程和程序的区别
    • LINUX进程管理
      • getpid()
      • getppid()
    • 进程的地址空间
    • 虚拟地址和物理地址
    • 进程状态管理
    • 进程相关命令
      • ps
    • top
    • pstree
    • kill
  • 进程的创建
    • 并发和并行
    • fork()
      • 父子进程执行不同的任务
      • 创建多个进程
  • 进程的退出
    • exit()和_exit()
      • exit()函数让当前进程退出,并且刷新缓冲区
      • _exit()
  • 进程的等待
    • wait()函数 和 waitpid()函数
      • wait()函数
        • 创建⼀个⼦进程, 延时 3s 后退出, ⽗进程等待⼦进程退出
      • waitpid()函数
        • 函数原型
        • 函数参数
  • 进程的替换
    • 在 Linux 系统中提供了⼀组⽤于进程替换的替换,共有 6 个函数
    • 示例:通过 execl 函数族执⾏ ls -l 命令

进程

进程的概念

进程(Process)是操作系统对一个正在运行的程序的一种抽象。它是系统运行程序的最小单位,是资源分配和调度的基本单位。

进程的特点如下

  1. 进程是⼀个独⽴的可调度的活动, 由操作系统进⾏统⼀调度, 相应的任务会被调度到cpu 中进⾏执⾏
    在这里插入图片描述

  2. 进程⼀旦产⽣,则需要分配相关资源,同时进程是资源分配的最⼩单位
    在这里插入图片描述

进程和程序的区别

  • 程序是静态的,它是⼀些保存在磁盘上的指令的有序集合,没有任何执⾏的概念
  • 进程是⼀个动态的概念,它是程序执⾏的过程,包括了动态创建、调度和消亡的整个过程
  • 并⾏执⾏ : 表示多个任务能够同时执⾏,依赖于物理的⽀持,⽐如 cpu是4核⼼,则可以同时执⾏4个任务
  • 并发执⾏ : 在同⼀时间段有多个任务在同时执⾏,由操作系统调度算法来实现,⽐较典型的就是时间⽚轮转
    在这里插入图片描述

LINUX进程管理

在 Linux 系统中管理进程使⽤树型管理⽅式

  • 每个进程都需要与其他某⼀个进程建⽴ ⽗⼦关系, 对应的进程则叫做 ⽗进程
  • Linux 系统会为每个进程分配 id , 这个 id 作为当前进程的唯⼀标识, 当进程结束, 则会回收

进程的 id 与 ⽗进程的 id 分别可以通过 getpid() 与 getppid() 来获取

getpid()

#include <unistd.h>

pid_t getpid(void);

该函数用来获取当前进程的 id

getppid()

#include <unistd.h>

pid_t getppid(void);

该函数用来获取当前进程的⽗进程的 id

进程的地址空间

  • ⼀旦进程建⽴之后, 系统则要为这个进程分配相应的资源, ⼀般系统会为每个进程分配 4G 的地址空间

  • 在这里插入图片描述

  • 4G 的进程地址空间主要分为两部分:
    0 - 3G : ⽤户空间
    3G - 4G : 内核空间

  • ⽤户空间⼜具体分为如下区间

stack : 存放⾮静态的局部变量

heap : 动态申请的内存

.bss : 未初始化过的全局变量(包括初始化为 0 的, 未初始化过的静态变量 (包括初始化为 0)

.data : 初始化过并且值不为 0 的全局变量, 初始化过的不为 0 静态变量

.rodata : 只读变量(字符串之类)

.text : 程序⽂本段(包括函数,符号常量)

  • 当⽤户进程需要通过内核获取资源时, 会切换到内核态运⾏, 这时当前进程会使⽤内核空间的资源⽤户需要切换到内核态运⾏时, 主要是通过 系统调⽤

虚拟地址和物理地址

  • 虚拟地址 : 程序运行时使用的地址, 由操作系统管理, 程序只能通过虚拟地址访问内存
  • 物理地址 : 实际物理内存中存储数据的地址, 由硬件管理, 程序只能通过物理地址访问内存
  • 虚拟地址和物理地址的转换关系由操作系统完成, 程序只能通过虚拟地址访问内存
  • 虚拟地址空间和物理地址空间的映射关系由操作系统完成, 程序只能通过虚拟地址访问内存

在 cpu 中有⼀个硬件 MMU(内存管理单元) , 负责虚拟地址与物理地址的映射管理以
及虚拟地址访问
操作系统可以设置 MMU 中的映射内存段

在这里插入图片描述

在操作系统中使⽤虚拟地址空间主要是基于以下原因:
直接访问物理地址, 会导致地址空间没有隔离, 很容易导致数据被修改
通过虚拟地址空间可以实现每个进程地址空间都是独⽴的,操作系统会映射到不⽤的
物理地址区间,在访问时互不⼲扰.

进程状态管理

进程是动态过程,操作系统内核在管理整个动态过程时会使⽤了
状态机,

  • 给不同时间节点设计⼀个状态,通过状态来确定当前的过程进度
  • 在管理动态过程时,使⽤状态机是⼀种⾮常好的⽅式

进程的状态⼀般分为如下

  • 运⾏态 (TASK_RUNNING) : 此时进程或者正在运⾏,或者准备运⾏, 就绪或者正在进⾏都属于运⾏态
  • 睡眠态 () : 此时进程在等待⼀个事件的发⽣或某种系统资源
    • 可中断的睡眠 (TASK_INTERRUPT) : 可以被信号唤醒或者等待事件或者资源就绪
    • 不可中断的睡眠 (TASK_UNTERRUPT) : 只能等待特定的事件或者资源就绪
  • 停⽌态 (TASK_STOPPED) : 进程暂停接受某种处理。例如:gdb 调试断点信息处理。
  • 僵死态(TASK_ZOMBIE):进程已经结束但是还没有释放进程资源

在这里插入图片描述

进程相关命令

ps

参数:

  • -e 显示所有进程
  • -f 显示进程详细信息
  • -l 显示进程详细信息,包括线程信息
  • -u 显示指定用户的进程
  • -aux 显示所有进程,包括其他用户的进程
ps -aux
ps -ef | grep " 进程名 "  # 查找进程

top

实时显示系统中进程的运行状态

top [-] [d delay] [q] [c] [S] [s] [i] [n] [b]

选项:

  • d : 改变显示的更新速度,或是在交谈式指令列 (interactive command) 按 s
  • q : 没有任何延迟的显示速度,如果使⽤者是有 superuser 的权限,则 top 将会以最⾼的优先序执⾏
  • c : 切换显示模式,共有两种模式,⼀是只显示执⾏档的名称,另⼀种是显示完整的路径与名称
  • S : 累积模式,会将⼰完成或消失的⼦进程 (dead child process) 的 CPU time 累积起来
  • s : 安全模式,将交谈式指令取消, 避免潜在的危机
  • i : 不显示任何闲置 (idle) 或⽆⽤ (zombie) 的进程
  • n : 更新的次数,完成后将会退出 top
  • b : 批次档模式,搭配 “n” 参数⼀起使⽤,可以⽤来将 top 的结果输出到档案内

在这里插入图片描述

top - 14:34:29 up 7 days, 18:51, 1 user, load average: 1.00, 0.95, 0.61

  • top:名称
  • 14:34:29 :系统当前时间
  • up 7 days, 14:30:系统以及运⾏的时间,和 uptime 命令相等
  • 1 users:当前有 1 个⽤户在线
  • load average: 1.00, 0.95, 0.61:系统负载,即任务队列的平均⻓度。 三个数值分别为 1 分钟、5 分钟、15 分钟前到现在的平均值。

Tasks: 290 total, 2 running, 287 sleeping, 0 stopped, 1 zombie

  • Tasks:任务,也就是进程
  • 290 total:当前总共有 290 个任务,也就是 290 个进程
  • 2 running:2 个进程正在运⾏
  • 287 sleeping:263 个进程正在休眠
  • 0 stopped:0 个停⽌的进程
  • 1 zombie:1 个僵⼫进程

%Cpu(s): 51.0 us, 0.7 sy, 0.0 ni, 47.8 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st

  • %Cpu(s):CPU 使⽤率
  • 51.0 us:⽤户空间占⽤ CPU 时间的百分⽐(⼤部分进程都运⾏在⽤户态,通常都是希望⽤户空间 CPU 越⾼越好)
  • 0.7 sy:内核空间占⽤ CPU 时间的百分⽐(Linux 内核态占⽤的 CPU 时间,系统 CPU 占⽤越⾼,表明系统某部分存在瓶颈。通常这个值越低越好)
  • 0.0 ni:占⽤ CPU 时间的百分⽐(ni 是 nice 的缩写,进程⽤户态的优先级,如果调整过优先级,那么展示的就是调整过 nice 值的进程消耗掉的 CPU 时间,如果系统中没有进程被调整过 nice 值,那么 ni 就显示为 0)
  • 47.8 id:空闲 CPU 占⽤率,等待进程运⾏
  • 0.0 wa:等待输⼊输出的 CPU 时间百分⽐(CPU 的处理速度是很快的,磁盘 IO 操作是⾮常慢的。wa 表示 CPU 在等待 IO 操作完成所花费的时间。系统不应该花费⼤量的时间来等待 IO操作,否则就说明 IO 存在瓶颈)
  • 0.0 hi:CPU 硬中断时间百分⽐(硬中断是硬盘、⽹卡等硬件设备发送给 CPU 的中断消息 )
  • 0.5 si:CPU 软中断时间百分⽐(软中断是由程序发出的中断 )
  • 0.0 st:被强制等待(involuntary wait)虚拟 CPU 的时间,此时 Hypervisor 在为另⼀个虚拟处理器服务。

MiB Mem : 3889.9 total, 366.0 free, 1535.2 used, 1988.6 buff/cache

  • MiB Mem:内存
  • 3889.9 total:物理内存总量
  • 366.0 free:空闲内存量
  • 1535.2 used:已使⽤的内存量
  • 1988.6 buff/cache:⽤作内核缓存的内存量

MiB Swap: 2048.0 total, 2035.2 free, 12.8 used. 2082.9 avail Mem

  • MiB Swap:交换空间(虚拟内存,当内存不⾜的时候,把⼀部分硬盘空间虚拟成内存使⽤)
  • 2048.0 total:交换区总量
  • 2035.2 free:空闲交换区总量
  • 12.8 used:使⽤的交换区总量
  • 2082.9 avail Mem:可⽤于启动⼀个新应⽤的内存(物理内存),和 free 不同,它计算的是可回收的 page cache 和 memory slab

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

  • PID:进程 id
  • USER:进程所有者
  • PR:进程的优先级,越⼩优先级越⾼
  • NI:nice 值,负值表示⾼优先级,正值表示低优先级
  • VIRT:进程使⽤的虚拟内存,单位是 kb
  • RES:进程使⽤的物理内存,单位 kb
  • SHR:进程使⽤的共享内存,单位 kb
  • S:进程状态(S 表示休眠,R 表示正在运⾏, Z 表示僵死状态,N 表示该进程优先值为负数,I 表示空闲状态)
  • %CPU:进程占⽤ CPU 时间的百分⽐
  • %MEM:进程占⽤内存的百分⽐
  • TIME+:进程实际运⾏的时间
  • COMMAND:进程的名称

pstree

显示进程树

在这里插入图片描述

kill

kill 命令是⽤于结束进程的命令或者⽤于显示相关信号

kill [选项] [参数]

选项:

  • -l : 显示信号名称
  • -s : 指定发送的信号
  • -a : 杀死进程组中的所有进程
  • -p : 杀死进程组中的进程,并将它们从进程组中剔除
  • -u : 指定用户
  • -signal : 发送指定的信号

参数:

  • 进程号: 要结束的进程号

进程的创建

并发和并行

  • 并发:多个任务在同⼀时间段被调度运行,⽐如同时有两个任务在运行,这就是并发。在有限的 cpu 核⼼的情况下(如只有⼀个 cpu 核⼼) , 利⽤快速交替 (时间⽚轮
    转) 执⾏来达到宏观上的同时执⾏

  • 并行:多个任务在不同时间段被调度运行,⽐如同时有两个任务在不同 CPU 上运行,这就是并行。在 cpu 多核的⽀持下,实现物理上的同时执⾏

并⾏是基于硬件完成,⽽并发则可以使⽤软件算法来完成, 在完成任务时,可以创建多个进程并发执⾏
在这里插入图片描述

fork()

创建子进程

返回值:

  • 0: 子进程
  • -1: 出错
    创建子进程的过程:
  • 父进程 fork() 系统调用,创建子进程,返回子进程的进程号
  • 子进程复制父进程的地址空间
  • 子进程从 fork() 系统调用返回,父进程继续执行
    在这里插入图片描述

⽗⼦进程并发执⾏, ⼦进程从 fork() 之后开始执⾏
⽗⼦进程的执⾏顺序由操作系统算法决定的,不是由程序本身决定
⼦进程会拷⻉⽗进程地址空间的内容, 包括缓冲区、⽂件描述符等 (COPY ON WRITE)

在这里插入图片描述

父子进程执行不同的任务

  • 使用 fork() 创建子进程,⽗进程和⼦进程可以并发执⾏不同的任务,
  • 执行不同的任务需要利用fork()函数返回值
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
    pid_t cpid;
    cpid = fork();
    if (cpid == -1){
        perror("[ERROR] fork()");
        exit(EXIT_FAILURE);
    }else if(cpid == 0){// 子进程
        printf("Child process task.\n");
        exit(EXIT_SUCCESS);
    }else if (cpid > 0){// 父进程
        printf("Parent process task.\n");
    }
    //父子进程都要执行的代码
    printf("Child and Process Process task.\n");
return 0;
}

创建多个进程

  • 在创建多个进程时, 最主要的原则为 由⽗进程统⼀创建,统⼀管理, 不能进⾏递归创建
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>


int main(){
    int cpid;
    cpid = fork();
    if (cpid == -1){
        perror("fork(): ");
        exit(EXIT_FAILURE);
    }else if (cpid == 0){// 子进程
        printf("The child process < %d > running...\n",getpid());
        sleep(2);
        printf("The child process < %d > has exited\n",getpid());
        exit(EXIT_SUCCESS);
    }else if (cpid > 0){// 父进程
        cpid = fork();
        if (cpid == -1){
            perror("fork(): ");
        }else if (cpid == 0){
            printf("The child process < %d > running...\n",getpid());
            sleep(3);
            printf("The child process < %d > has exited\n",getpid());
            exit(EXIT_SUCCESS);
        }else if (cpid > 0){

        }
    }
    return 0;
}

进程的退出

在进程结束时,需要释放进程地址空间 以及内核中产⽣的各种数据结构
资源的释放需要通过调⽤ exit 函数或者 _exit 函数来完成
在程序结束时,会自动调⽤ exit 函数

exit()和_exit()

exit()函数让当前进程退出,并且刷新缓冲区

#include <stdlib.h>
void exit(int status);

参数:

  • status:进程退出状态
  • 系统中定义了 EXIT_SUCCESS 和 EXIT_FAILURE 两个宏,用来表示成功和失败的状态码,具体定义在头文件 stdlib.h 中

#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0

示例:
创建⼀个⼦进程,让⼦进程延时 3 s 后退出


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(){

pid_t cpid;
cpid = fork();
if (cpid == -1){
perror("[ERROR] fork(): ");
exit(EXIT_FAILURE);
}else if(cpid == 0){printf("Child Process < %d > running...\n",getpid());
sleep(3);
printf("Child Process < %d >  has exited.\n",getpid());
exit(EXIT_SUCCESS);
}else if(cpid > 0){
sleep(5);
}
return 0;
}

_exit()

exit 函数与 _exit 函数功能相似, 但有很多不同, 具体如下:

  • _exit() 属于系统调⽤, 能够使进程停⽌运⾏, 并释放空间以及销毁内核中的各种数据结构
  • exit() 基于_exit() 函数实现, 属于库函数, 可以清理 I/O 缓冲区

进程的等待

  • 在⼦进程运⾏结束后,进⼊僵死状态, 并释放资源, ⼦进程在内核中的 数据结构 依然保留
  • ⽗进程 调⽤ wait() 与 waitpid() 函数等待⼦进程退出后,释放⼦进程遗留的资源

task_struct 结构体随着进程的创建而创建和销毁而销毁, 它包含了进程的所有信息, 包括进程号、进程状态、进程调度信息、进程资源使用信息等

wait()函数 和 waitpid()函数

wait()函数

函数头文件

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);

功能:
让函数调⽤者进程进⼊到睡眠状态, 等待⼦进程进⼊僵死状态后,释放相关资源并返回

参数:

  • wstatus: 指向整数的指针,用来接收⼦进程的退出状态

获取具体值需要使⽤ WEXITSTATUS() 宏定义

返回:

  • 若成功,返回值是⼦进程的进程号
  • 若出错,返回值是 -1

会阻塞调⽤者进程(⼀般为⽗进程)
在⼦进程状态为僵死态时,回收资源,并释放资源后返回

创建⼀个⼦进程, 延时 3s 后退出, ⽗进程等待⼦进程退出
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
    pid_t cpid;
    cpid = fork();
    if (cpid == -1){
        perror("[ERROR] fork(): ");
        exit(EXIT_FAILURE);
    }else if(cpid == 0){
        printf("The Child process < %d > running...\n",getpid());
        sleep(3);
        exit(88);
    }else if(cpid > 0){
        int rpid,status = 0;
        rpid = wait(&status);//会阻塞父进程,等待子进程的状态变化,自动释放资源并返回
        if (rpid == -1){
            perror("[ERROR] wait() : ");
            exit(EXIT_FAILURE);
        }
        printf("The Child Process < %d > has exited,exit code < %d >.\n",rpid,WEXITSTATUS(status));
    }
    return 0;
}

在 wait 存储在 satus 变量的值, 存储了很多信息, 通过⼀系列 W 开头的宏来解析获取

WIFEXITED(status) : 进程是否正常结束

WEXITSTATUS(wstatus) : 获取进程退出状态值, exit 函数的参数

WIFSIGNALED(wstatus) : 表示该⼦进程是否被信号结束的, 返回真,则表示被信号结束的

WTERMSIG(wstatus) : 返回结束该⼦进程的那个信号的信号值

WCOREDUMP(wstatus) : 表示该⼦进程被信号唤醒的

WIFSTOPPED(wstatus) : 表示该⼦进程是否被信号中⽌ (stop) 的 , 返回真,则表示是被信号中⽌的

waitpid()函数

waitpid 函数的功能与 wait 函数⼀样,但⽐ wait() 函数功能更强⼤, waitpid() 函数可以指定等待的进程

####函数头⽂件

#include <sys/types.h>
#include <sys/wait.h>
函数原型
pid_t waitpid(pid_t pid, int *wstatus, int options);
函数参数

pid : 进程 id

  • -1 : 可以等待任意⼦进程
  • >0 : 等待 id 为 pid 的进程

wstatus : 保存⼦进程退出状态值变量的指针

options : 选项

  • WNOHANG : ⾮阻塞选项 // 若没有可等待的进程, 则返回 0, 否则返回 -1
  • WUNTRACED : 等待被跟踪的进程
  • WCONTINUED : 继续被跟踪的进程
  • WEXITED : 等待退出的进程
  • WSTOPPED : 等待停止的进程
  • WNOWAIT : 不创建新的进程组
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
    pid_t cpid;
    cpid = fork();
    if (cpid == -1){
        perror("[ERROR] fork(): ");
        exit(EXIT_FAILURE);
    }else if(cpid == 0){
        printf("The Child process < %d > running...\n",getpid());
        sleep(3);
        exit(88);
    }else if(cpid > 0){int rpid,status = 0;
        //rpid = waitpid(-1,&status,0);//-1是等待任意子进程退出 // 0是默认阻塞的
        rpid = waitpid(-1,&status,WNOHANG);//WNOHANG是非阻塞
        if (rpid == -1){
            perror("[ERROR] wait() : ");
            exit(EXIT_FAILURE);
        }
#if 0
        //没有子进程退出就返回0
        while((rpid = waitpid(-1,&status,WNOHANG)) == 0){
}
#endif
        printf("The Child Process < %d > has exited,exit code < %d >.\n",rpid,WEXITSTATUS(status));
    }
    return 0;
}

进程的替换

创建⼀个进程后,pid 以及在内核中的信息保持 保持不变, 但进程所执⾏的代码进⾏替换

作⽤ : 通过⼀个进程启动另外⼀个进程

在这里插入图片描述

应⽤场景:Linux 终端应⽤程序,执⾏命令时,通过创建⼀个进程后,在替换成命令的可执⾏程序再执⾏

在这里插入图片描述

在 Linux 系统中提供了⼀组⽤于进程替换的替换,共有 6 个函数

函数原型:

int execl (const char *__path, const char *__arg, ... / (char *) NULL */)
 > pathname 指向一个字符数组,即字符串。这个字符串表示可执行文件的路径
 > arg 指向一个字符数组,即命令行参数。这个参数列表可以为空。
 > 省略号 ... 表示可变参数列表,它允许传递任意数量的参数给可执行文件,包括命令行参数。在参数列表的最后必须以 (char *) NULL 来指示结束。
 > NULL 是一个字符型指针表示空值,用来指示参数列表的结束。


int execlp(const char *file, const char arg,/ (char *) NULL */);

int execle(const char *pathname, const char arg,/, (char *) NULL, char *const envp[] */);

int execv(const char *pathname, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execvpe(const char *file, char *const argv[], char *const envp[]);

> 函数参数:
        path:可执文件的路径名
        file : 可执文件名,可以通过 path 环境变量指定的路径
        arg : 参数列表,以 NULL 结尾
        argv[] : 参数数组
        envp[] : 环境变量数组
> 函数返回值:
        成功 : 0
        失败 : -1

示例:通过 execl 函数族执⾏ ls -l 命令

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
    int ret;

#if 0
    ret = execl("/bin/ls","ls","-l",NULL);//替换当前进程,启动ls命令
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);//退出当前进程
    }
#endif

    char *const argv[]={"ls","-l",NULL};//参数列表
    ret= execv("/bin/ls",argv);//替换当前进程,启动ls命令
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);
    }

     //env可以查看环境变量
    ret= execlp("ls","ls","-l",NULL);//函数会搜索环境变量当作路径
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);
    }

    
    return 0;
}
//这个操作替换了当前进程,启动了另外的程序
//一般是先创建子进程,然后在子进程中调用 execl 函数族,替换子进程
//替换当前进程,启动ls命令
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);//退出当前进程
    }
#endif

    char *const argv[]={"ls","-l",NULL};//参数列表
    ret= execv("/bin/ls",argv);//替换当前进程,启动ls命令
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);
    }

     //env可以查看环境变量
    ret= execlp("ls","ls","-l",NULL);//函数会搜索环境变量当作路径
    if (ret == -1){
        perror("[ERROR] execl(): ");
        exit(EXIT_FAILURE);
    }

    
    return 0;
}
//这个操作替换了当前进程,启动了另外的程序
//一般是先创建子进程,然后在子进程中调用 execl 函数族,替换子进程

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微短剧市场还能火多久?短剧小程序是否有必要搭建?,现在入场到底晚不晚?

我公司在2019年开始都是做软件开发的&#xff0c;从2022到现在&#xff08;2024&#xff09;特别深有体会&#xff0c;在2022年的时候我公司还是在全部做外包项目&#xff0c;一年大概遇到了10多个咨询短剧领域的软件定制&#xff0c;但是当时我只是以为是一个影视播放的程序&a…

7.优化算法之分治-快排归并

0.分治 分而治之 1.颜色分类 75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;并按照红色、白色、蓝色顺序排列。 我们使用整数…

推动多模态智能模型发展:大型视觉语言模型综合多模态评测基准

随着人工智能技术的飞速发展&#xff0c;大型视觉语言模型&#xff08;LVLMs&#xff09;在多模态应用领域取得了显著进展。然而&#xff0c;现有的多模态评估基准测试在跟踪LVLMs发展方面存在不足。为了填补这一空白&#xff0c;本文介绍了MMT-Bench&#xff0c;这是一个全面的…

Django 模版继承

1&#xff0c;设计母版页 Test/templates/6/base.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><!-- 修正了模板标签的全角字符问题 -->{% block title %}<title>这个是母版页</title>{…

leetCode.93. 复原 IP 地址

leetCode.93. 复原 IP 地址 题目思路&#xff1a; 代码 // 前导零的判断方法&#xff1a;如果第一个数是0&#xff0c;且第二个数还有数据&#xff0c;那就是前导0&#xff0c;要排除的 // 注意跟单个 0 区分开 class Solution { public:vector<string> res;vector<…

Opencv+python模板匹配

我们经常玩匹配图像或者找相似&#xff0c;opencv可以很好实现这个简单的小功能。 模板是被查找目标的图像&#xff0c;查找模板在原始图像中的哪个位置的过程就叫模板匹配。OpenCV提供的matchTemplate()方法就是模板匹配方法&#xff0c;其语法如下&#xff1a; result cv2.…

【活动感想】筑梦之旅·AI共创工坊 workshop 会议回顾

目录 &#x1f30a;1. 会议详情 &#x1f30a;2. 会议回顾 &#x1f30d;2.1 主持人开场 &#x1f30d;2.2 元甲-小当家 AI 驱动的创意儿童营养早餐料理机&今天吃什么App &#x1f30d;2.3 Steven- A l 心理疗愈认知 &#x1f30d;2.4 伯棠-诸子百家(xExperts)-多智能…

私有部署Twikoo评论系统

原文&#xff1a;https://blog.c12th.cn/archives/12.html 前言 以前用 MongoDB Vercel 搭建 Twikoo 老是有点小问题&#xff0c;所以就放弃了。无意中看到可以用 docker 来搭建&#xff0c;正好有台服务器可以尝试下。 私有部署 Twikoo 版本要求 1.6.0 或以上 &#xff0c; …

AMD Anti-Lag 2抗延迟技术落地 CS2首发、延迟缩短95%

AMD发布了全新重磅驱动程序Adrenalin 24.6.1版本&#xff0c;包括首发落地Anti-Lag 2抗延迟技术、优化支持新游戏、升级支持HYPR-Tune、支持新操作系统、优化AI加速与开发、扩展支持Agility SDK、修复已知Bug&#xff0c;等等。 一、Anti-Lag 2 今年5月份刚宣布&#xff0c;重…

【计算机毕业设计】基于Springboot的智能物流管理系统【源码+lw+部署文档】

包含论文源码的压缩包较大&#xff0c;请私信或者加我的绿色小软件获取 免责声明&#xff1a;资料部分来源于合法的互联网渠道收集和整理&#xff0c;部分自己学习积累成果&#xff0c;供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者…

信号与系统-实验6-离散时间系统的 Z 域分析

一、实验目的 1、掌握 z 变换及其性质&#xff1b;了解常用序列的 z 变换、逆 z 变换&#xff1b; 2、掌握利用 MATLAB 的符号运算实现 z 变换&#xff1b; 3、掌握利用 MATLAB 绘制离散系统零、极点图的方法&#xff1b; 4、掌握利用 MATLAB 分析离散系统零、极点的方法&a…

kicad第三方插件安装问题

在使用KICAD时想安装扩展内容&#xff0c;但是遇到下载失败&#xff0c;因为SSL connect error。 因为是公司网络&#xff0c;我也不是很懂&#xff0c;只能另寻他法。找到如下方法可以曲线救国。 第三方插件包目录 打开存放第三方插件存放目录&#xff0c;用于存放下载插件包…

vue3+vite+nodejs,通过接口的形式请求后端打包(可打包全部或指定打包组件)

项目地址https://gitee.com/sybb011016/test_build 打包通过按钮的形式请求接口&#xff0c;让后端进行打包&#xff0c;后端使用express-generator搭建模版。前端项目就在npm init vuelatest基础上添加了路由 如果只想打包AboutView组件&#xff0c;首先修改后端接口。 //打…

Linux如何安装openjdk1.8

文章目录 Centosyum安装jdk和JRE配置全局环境变量验证ubuntu使用APT(适用于Ubuntu 16.04及以上版本)使用PPA(可选,适用于需要特定版本或旧版Ubuntu)Centos yum安装jdk和JRE yum install java-1.8.0-openjdk-devel.x86_64 安装后的目录 配置全局环境变量 vim /etc/pr…

运营商、银行、国企等单位开发岗24届Offer薪资与福利汇总

本文介绍24届校园招聘中&#xff0c;地理信息科学&#xff08;GIS&#xff09;专业硕士研究生所得Offer的整体薪资情况、福利待遇等。 在2024届秋招与春招中&#xff0c;我累计投递了170余个单位&#xff0c;获得17个Offer&#xff1b;平均每投递10个简历才能获得1个Offer。说句…

2024年6月29日 每周新增游戏

图吧工具箱: 全名图拉丁吧硬件检测工具箱,是开源、免费、绿色、纯净的硬件检测工具合集,专为图钉及所有DIY爱好者制作,包含常用硬件测试和检测工具,月工JS必备! iGuzheng爱古筝iguzheng古筝是一款可以在线模拟古筝练习的软件&#xff0c;用户可以直接在手机上练习古筝&#xff…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 6月30日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年6月30日 星期日 农历五月廿五 1、 气象台继续发布暴雨红色预警&#xff1a;30日&#xff0c;安徽、湖南等地局地有特大暴雨。 2、 稀土管理条例公布&#xff1a;任何组织和个人不得侵占或者破坏稀土资源。 3、 暑期全国将…

ubuntu丢失网络/网卡的一种原因解决方案

现象 开机进入ubuntu后发现没有网络&#xff0c;无论是在桌面顶部状态栏的快捷键 还是 系统设置中&#xff0c;都没有”有线网“和”无线网“的选项&#xff0c;”代理“的选项是有的使用数据线连接电脑和手机&#xff0c;手机开启”通过usb共享网络“&#xff0c;还是没有任何…

Parzen 窗估计法

本篇文章是博主在人工智能等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学习笔记&#…

一文弄懂逻辑回归算法

1. 引言 今天我们将深入探讨另一种基本的机器学习算法&#xff1a;逻辑回归。在前两篇文章中&#xff0c;我们使用线性回归和梯度下降法帮助我们的朋友马克确定了他 2400 平方英尺房子的理想售价。 最近马克再次向我们求助。他住在一个高档社区&#xff0c;他认为低于一定面积…