当前位置: 首页 > news >正文

【进程等待】waitpid的参数pid | status的位图位操作WIFEXITEDWEXITSTATUS宏

目录

waitpid

pid

status

status位图 

status按位操作

输入型参数和输入型参数 

宏WIFEXITED&WEXITSTATUS

options&非阻塞等待


上篇进程等待我们介绍到怎样去进程等待。我们介绍了wait函数&阻塞等待。本篇我们将介绍waitpid函数的参数pid和status。

waitpid

  • man 2 waitpid
  • 等待一个进程的状态发生变化
  • pit_t pid是父进程等待的子进程的pid,情况有3种,这里介绍两种情况。
  • int *status是NULL
  • int options是0
  • 先把后面两个参数设置为NULL和0

pid_ t waitpid(pid_t pid, int *status, int options);
返回值

  • 当正常返回的时候waitpid返回收集到的子进程的进程ID;
  • 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
  • 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

参数
pid:

  • Pid=-1,等待任一个子进程。与wait等效。
  • Pid>0.等待其进程ID与pid相等的子进程。

status:

  • WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
  • WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

options:

  • WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

waitpid是一个在Unix和类Unix系统(如Linux)中常用的系统调用,用于等待一个或多个子进程的状态改变。与wait系统调用相比,waitpid提供了更多的灵活性,因为它允许你指定要等待的子进程的PID(进程ID),并可以设置等待的模式(阻塞或非阻塞)。

以下是waitpid函数的原型和参数详解:

pid_t waitpid(pid_t pid, int *status, int options);
  • pid:这是一个整数,用于指定要等待的子进程的PID。其取值有以下几种情况:
    • pid > 0:等待指定PID为pid的子进程。
    • pid = 0:等待当前进程组中的任何子进程。
    • pid = -1:等待任何子进程,与wait函数的功能相同。
    • pid < -1:等待组ID为-pid的任意子进程。
  • status:这是一个指向整数的指针,用于存储子进程的退出状态。如果不需要这些信息,可以将此参数设置为NULL。
  • options:这是一个位掩码,用于修改waitpid的行为。常见的选项有:
    • WNOHANG:使waitpid调用变为非阻塞。如果没有子进程满足条件,waitpid会立即返回。
    • WUNTRACED:当子进程被停止时(而不是退出时),也返回它的状态。这通常与跟踪被调试的子进程有关。
    • WCONTINUED:当被停止的子进程恢复时,返回它的状态。

waitpid的返回值有以下几种情况:

  • 如果成功,返回收集到的子进程的PID。
  • 如果设置了WNOHANG选项并且没有子进程满足条件,返回0。
  • 如果在调用中出现错误,返回-1,并设置全局变量errno以指示错误。

waitpid是一个非常有用的工具,允许你更精细地控制和管理你的子进程。

pid

  • 这样设置waitpid的参数,waitpid(-1,NULL,0)和 wait(NULL)的功能一致
  • pid = -1表示等待任何一个子进程的退出
  • pid > 0表示等待指定的一个子进程的退出
  • pid为错误数字。wait fail !(只要pid不输入错误❌一般父进程都不会等待失败)
  • fork返回值
  1. 0是子进程执行
  2. >0返回的是子进程的pid 是父进程执行(id是子进程的pid数值)

pid:这是一个整数,用于指定要等待的子进程的PID。其取值有以下几种情况:

  • pid > 0:等待指定PID为pid的子进程。
  • pid = 0:等待当前进程组中的任何子进程。
  • pid = -1:等待任何子进程,与wait函数的功能相同。
  • pid < -1:等待组ID为-pid的任意子进程。
 myprocess.c  1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 #include<stdlib.h>5 #include<sys/types.h>6 #include<sys/wait.h>7 8 void ChildRun()9 {10   int cnt = 5;11   while(cnt--)12   {13     printf("I am child,pid: %d,ppid: %d,cnt: %d\n",getpid(),getppid()    ,cnt);14     sleep(1);15   }16 }17 18 int main()19 {20   printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进>    程21   pid_t id = fork();                                                 22   if(id == 0)//child子进程23   {24     //子进程循环运行25     ChildRun();26     printf("Child quit...\n");27     exit(0);//终止进程,子进程直接僵尸28   }29   //father30   //父进程,父进程在子进程运行期间5ms一直在等待....31   //pid_t rid = wait(NULL); 32   pid_t rid = waitpid(id,NULL,0);33   if(rid > 0)34   {35     printf("wait success,rid: %d\n",rid);36   } 37   sleep(3);38   printf("father quit ... \n");39 }

【错误的pid演示】

//father31   //父进程,父进程在子进程运行期间5ms一直在等待.... 32   pid_t rid = waitpid(id+1 , NULL , 0);33   if(rid > 0)34   {35     printf("wait success,rid: %d\n",rid);36   }37   else38   {39     printf("wait fail !\n");40   }41   sleep(3);42   printf("father quit ... \n");                     

 

status

status:这是一个指向整数的指针,用于存储子进程的退出状态。如果不需要这些信息,可以将此参数设置为NULL。

  • int *status表示通过等待获取子进程的退出信息。(❗前面的进程终止已知进程终止的退出信息表示退出码&退出信号
  • 父进程通过waitpid等待子进程,通过第二个参数就可以拿到子进程的退出信息(status是输出型参数)
  • 当然也存在父进程不关心子进程的退出信息,&status直接置为NULL即可。(等待是必须的,但是获取子进程的退出信息不是必须的)
  • status不能简单的当作整形来看待,可以当作位图来看待,存在特定的格式。
  • status是输出型参数。
  • status按位操作拿到退出码和退出信号。
  • status通过下面两个宏拿到退出码和退出信号。
  1. WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
  2. WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码。

有人问可不可以不用waitpid传递子进程的退出信息,直接定义两个全局变量exit_code,exit_signal。在子进程退出的时候写入自己的退出信息到全局变量当中❓

  • 当然不可以,全局也是数据。虽然一开始是被父子进程共享,当子进程要写入的时候,会发生写时拷贝,此刻父子进程都有一份各自的全局变量的数据,父进程是看不到的子进程写入自己的全局变量的数据。
  • 所以只能通过waitpid的status参数。下面我们来仔细学习以下☞☞

status位图 

怎么把子进程的退出信息(退出码和退出信号)整合成一个数字赋值给status呢❓

  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待,存在特定的格式,32比特位具体细节如下图(只研究status低16比特位)
  1. 32比特位只使用低16比特位
  2. 其中次低8位:进程退出时所对应的退出状态(退出码)
  3. 其中最低7位:进程退出时是否受到终止信号(退出信号)
  4. 第8位:暂时不考虑,后面进程信号会讲
  • 所以,退出状态的取值范围是[0,255],退出信号取值范围:[0,127]
  • status是以位图的形式把子进程的退出码和退出信息返回给父进程的

在Linux的waitpid函数中,status参数是一个指向整数的指针,它用于存储子进程的退出状态信息。尽管status本身是一个整型指针,但我们更关心的是它所指向的那个整数变量的取值范围和内容。

  • 这个整数变量(我们称之为status_val)通常用于表示子进程的退出状态。在大多数情况下,我们只关心这个整数的低16位,因为高16位通常不被使用。
  • 正常退出:如果子进程正常退出(即调用了exit()函数),那么status_val的低16位的高8位将保存子进程的返回值(范围是0-255)。低8位中的低7位将被设置为0,而最高位(第8位)通常被用来表示一个标志位,以区分是正常退出还是由于信号而退出。
  • 异常退出:如果子进程由于接收到一个信号而退出,那么status_val的低16位的低7位将保存导致子进程退出的信号的编号(范围通常是1-127,但取决于系统和信号的具体实现)。同样,最高位(第8位)将用于表示是由于信号而退出。
  • 为了从status_val中提取这些信息,可以使用一些宏(如WEXITSTATUSWTERMSIG等)来进行位操作和提取。

  • 因此,status本身并没有一个固定的取值范围,因为它只是一个指针。但它所指向的那个整数变量(status_val)的取值范围和内容则取决于子进程的退出状态。

 

status按位操作

我们知道子进程的退出码和退出信息被父进程调用waitpid等待时,赋值给status参数。如果我们想要在父进程里面查看详细的子进程的退出码和退出信息🆗请看下面代码。

  • 正常退出:(status>>8)&0xFF
  • 异常退出:status&0x7F
  • 解释☞位操作专题。
//....同上18 int main()19 {20   printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进程21   pid_t id = fork();22   if(id == 0)//child子进程23   {24     //子进程循环运行25     ChildRun();26     printf("Child quit...\n");27     exit(1);//终止进程,子进程直接僵尸28   }29   //father30   //父进程,父进程在子进程运行期间5ms一直在等待.... 31   int status = 0;32   pid_t rid = waitpid(id, &status, 0);33   if(rid > 0)34   {35     printf("wait success,rid: %d\n",rid);36   }37   else38   {39     printf("wait fail !\n");40   }41   sleep(3);42   printf("father quit,status: %d,code: %d,signal: %d\n",status, (status>>8)&0XFF,status&0X7F);            43 }

【kill -9 pid错误测试】

【野指针错误测试】

输入型参数和输入型参数 

在函数或系统调用的参数中,我们通常区分输入型参数(Input Parameters)和输出型参数(Output Parameters)。这些参数在函数或系统调用的执行过程中扮演不同的角色。

  1. 输入型参数(Input Parameters)

    • 这些参数是函数或系统调用所需的信息或数据,用于执行特定的任务或操作。
    • 它们通常由调用者(Caller)提供,并在函数或系统调用内部被使用。
    • 输入型参数的值在函数或系统调用执行前后不会改变(除非函数或系统调用有特定的功能去修改它们)。
    • waitpid函数中,pidoptions是输入型参数。pid指定了要等待的子进程的PID,而options则设置了等待的行为(如阻塞或非阻塞)。
  2. 输出型参数(Output Parameters)

    • 这些参数用于存储函数或系统调用的结果或返回的数据。
    • 它们通常在函数或系统调用执行前未定义或具有初始值,但在执行后被赋值或更新。
    • 输出型参数的值在函数或系统调用执行后会被改变。
    • waitpid函数中,status是输出型参数。它用于存储子进程的退出状态信息,这些信息在函数执行前是未知的。

总结:输入型参数是函数或系统调用所需的信息,而输出型参数则用于存储函数或系统调用的结果。在调用函数或系统调用时,正确设置输入型参数和处理输出型参数是非常重要的。

【输入型参数VS输出型参数】简而言之,输入型参数是调用者提供,输出型参数是程序赋值提供 

宏WIFEXITED&WEXITSTATUS

除了用status通过按位操作来提取子进程的退出码和退出信号,有没有其他方法❓ 

  • status按位操作不方便,介绍两个宏。(本质上就是status按位操作封装的)
  • WIFEXITED(status): 若为正常终止子进程返回状态,则为真。查看进程是否是正常退出
  • WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。查看进程的退出码 
  • WIFEXITED:W:wait  IF:if  EXITED:exited(等待退出)
  • WEXITSTATUS:W:wait  EXIT:exit  STATUS:status(等待退出状态)
  • 本质是:检查退出信号sign位也就是status的低7位是否位0,为0则是正常退出。非0则是异常退出。若是正常退出则若用户愿意可以用WEXITSTATUS查看退出码。
  • ❗可以用这两个宏来判断是否退出为正常。
 1: myprocess.c1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 #include<stdlib.h>5 #include<sys/types.h>6 #include<sys/wait.h>7 8 void ChildRun()9 {                                                                                                        10   int cnt = 5;11   while(cnt--)12   {13     printf("I am child,pid: %d,ppid: %d,cnt: %d\n",getpid(),getppid(),cnt);14     sleep(1);15   }16 }17 18 int main()19 {20   printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进程21   pid_t id = fork();22   if(id == 0)//child子进程23   {24     //子进程循环运行25     ChildRun();26     printf("Child quit...\n");27     exit(1);//终止进程,子进程直接僵尸28   }29   //father30   //父进程,父进程在子进程运行期间5ms一直在等待.... 31   int status = 0;32   pid_t rid = waitpid(id, &status, 0);33   if(rid > 0)34   {35     if(WIFEXITED(status))36     {37       printf("child quit normal,child exit code: %d\n",WEXITSTATUS(status));38     }39     else40     {41       printf("child quit unnormal!\n");42     }43     printf("wait success,rid: %d\n",rid);                                                                44   }45   else46   {47     printf("wait fail !\n");48   }49   sleep(3);50  //printf("father quit,status: %d,code: %d,signal: %d\n",status,(status>>8)&0XFF,status&0X7F);51 }

options&非阻塞等待

前面讲到在子进程运行期间,父进程一直在等待,能不能干点别的事情❓  

options:这是一个位掩码,用于修改waitpid的行为。常见的选项有:

  • WNOHANG:使waitpid调用变为非阻塞。如果没有子进程满足条件,waitpid会立即返回。
  • WUNTRACED:当子进程被停止时(而不是退出时),也返回它的状态。这通常与跟踪被调试的子进程有关。
  • WCONTINUED:当被停止的子进程恢复时,返回它的状态。

🙂感谢大家的阅读,若有错误和不足,欢迎指正。下篇阻塞等待和非阻塞等待以及waitpid的最后一个参数。

相关文章:

【进程等待】waitpid的参数pid | status的位图位操作WIFEXITEDWEXITSTATUS宏

目录 waitpid pid status status位图 status按位操作 输入型参数和输入型参数 宏WIFEXITED&WEXITSTATUS options&非阻塞等待 上篇进程等待我们介绍到怎样去进程等待。我们介绍了wait函数&阻塞等待。本篇我们将介绍waitpid函数的参数pid和status。 waitp…...

unity---常用API

1. Vector3&#xff1a;结构体由x、y、z这3个数值组成&#xff0c;表示一个向量 magnitude变量返回该向量的长度normalized变量返回 magnitude 为 1 时的该向量zero静态变量Vector3(0, 0, 0)one静态变量Vector3(1, 1, 1)forward静态变量Vector3(0, 0, 1)back静态变量Vector3(0…...

设计模式: 模板模式

目录 一&#xff0c;模板模式 二&#xff0c;特点 三&#xff0c;组成部分 四&#xff0c;实现步骤 五&#xff0c;案例 一&#xff0c;模板模式 模板模式&#xff08;Template Pattern&#xff09;是一种行为型设计模式&#xff0c;它在超类中定义了一个算法的骨架&#…...

[虚拟机+单机]梦幻契约H5修复版_附GM工具

本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff01; 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行的&#xff0c;踩过的坑都给你们填上了 视频演示 [虚拟机单…...

头文件相互包含 前向声明

当两个类需要相互访问对方的成员或方法时&#xff0c;通常意味着它们之间存在某种依赖关系。这种依赖关系可能源于类的设计或功能需求。以下是一个简单的例子&#xff0c;展示了当两个类需要相互访问对方成员或方法时&#xff0c;如何使用包含对方头文件的方式来解决循环包含的…...

七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统

七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统 员工上班刷视频&#xff01; 员工上班炒股&#xff01; 员工上班干副业&#xff01; 碰见这种情况怎么办&#xff1f;当然是用电脑监控软件来监视员工的一举一动了&#xff0c;那么这样的软件有哪些呢&#…...

centos7-bcc 安装

检查 内核信息 确保安装的kernel-dev 和内核版本一致!!! rpm -qa|grep kernel kernel-tools-3.10.0-1160.92.1.el7.x86_64 kernel-devel-3.10.0-1160.92.1.el7.x86_64 kernel-headers-3.10.0-1160.92.1.el7.x86_64 kernel-3.10.0-1160.92.1.el7.x86_64 kernel-tools-libs-3.1…...

5.06号模拟前端面试8问

5.06号模拟前端面试8问 1.promise如何实现then处理 在JavaScript中&#xff0c;Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态&#xff1a;pending&#xff08;等待&#xff09;&#xff0c;fulfilled&#xff08;完成&#xff09;&#xff0c;rejected&…...

解读Inscode AI:开启代码智能化的新时代

导语&#xff1a; 近年来&#xff0c;人工智能技术的迅猛发展已经深刻地影响着各个行业&#xff0c;而在软件开发领域&#xff0c;Inscode AI的出现无疑将给代码智能化带来一场革命。本文将为大家解读Inscode AI的特点和应用&#xff0c;探索其如何改变我们的软件开发方式。 一…...

快速了解Vuex

Vuex Vuex使用Vuex Vuex &#x1f4cc;vuex 是一个专为 Vue.js 应用程序开发的状态管理库 &#x1f4cc;vuex 可以在多个组件之间共享数据&#xff0c;并且共享的数据是响应式的&#xff0c;即数据的变更能及时渲染到模板 &#x1f4cc;vuex 采用集中式存储管理所有组件的状态…...

vue管理系统导航中添加新的iconfont的图标

1.在官网上将需要的图标&#xff0c;加入项目中&#xff0c;下载 2.下载的压缩包中&#xff0c;可以选择这两个&#xff0c;复制到项目目录中 3.如果和之前的iconfont有重复&#xff0c;那么就重新命名 4.将这里的.ttf文件&#xff0c;也重命名为自己的 5.在main文件中导入 6.在…...

Docker的介绍及与传统虚拟化技术的区别

Docker是一个开源的应用容器引擎&#xff0c;它使得开发者可以将应用及其依赖包打包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上。Docker基于Go语言开发&#xff0c;它的出现极大地简化了应用程序的部署、管理和扩展。 以下是Docker…...

06.Git远程仓库

Git远程仓库 #仓库种类&#xff0c;举例说明 github gitlab gitee #以这个仓库为例子操作登录码云 https://gitee.com/projects/new 创建仓库 选择ssh方式 需要配置ssh公钥 在系统上获取公钥输入命令&#xff1a;ssh-keygen 查看文件&#xff0c;复制公钥信息内…...

Anaconda安装和深度学习环境的安装(TensorFlow、Pytorch)

换了新电脑&#xff0c;重新装一下anaconda这些编程环境。好久没装过了&#xff0c;自己也需要查查资料&#xff0c;然后记录一下&#xff0c;分享给别人。 目标&#xff0c;三个环境&#xff1a;1.anaconda基础环境&#xff08;包含xgboost和lightgbm&#xff09;&#xff0c…...

元素设置 flex:1,但是会被内部长单词宽度超出拉伸

初始布局如上图&#xff0c;left中是代码编辑器&#xff0c;实际上是个文本域&#xff0c;当输入长文本过长时&#xff0c;left宽度会被拉伸。 右侧容器被挤压。 解决方案&#xff1a;width&#xff1a;0&#xff1b; .left{flex:1; width:0} 当输入长文本过长时&#xff0c…...

win11 安装oracle11g详细流程及问题总结

1.安装包下载地址 本案例操作系统&#xff0c; Oracle 11g下载-Oracle 11g 64位/32位下载官方版(附详细的安装图解教程) - 多多软件站多多为大家免费提供Oracle 11g下载&#xff0c;包含64位/32位官方版本&#xff0c;并附详细的Oracle 11g安装图解教程&#xff0c;同时希望能…...

自我模拟面试

在面试中&#xff0c;你如何面对面试官呢&#xff1f; 我认为&#xff0c;对于面试官提出的问题&#xff0c;如果你不会&#xff0c;那就是不会。你的思考过程&#xff0c;实际上就是将你平时所学的&#xff0c;所了解的&#xff0c;在脑海中进行一次复习&#xff0c;就像当别…...

头歌java面向对象基础

第一关类的定义 package step1;// ---------------------Begin------------------------ public class Student{String name"李四";int age18;public void speak(){System.out.println("我爱学习");} }// ---------------------End----------------------…...

PMP课程知识点很多,无法入手,该如何学习?

回顾整个学习过程&#xff0c;我花费了不少时间&#xff0c;但也学到了系统的项目管理知识&#xff0c;考试结果也让我感到满意。在学习过程中&#xff0c;我认为以下几点非常重要&#xff1a; 1、需要对课本进行整体阅读&#xff0c;以便对内容有一个整体印象&#xff1b; 2…...

隔离流量优化网络传输

不要将长流和短突发流(或者大象流和老鼠流)混部在一起&#xff0c;我建议用切片或虚通道将它们在全链路范围彻底隔离&#xff0c;而不仅仅在交换机上配合着大肆宣讲的高端包分类算法配置一些排队调度。 也不必扯泊松到达&#xff0c;帕累托分布&#xff0c;这些概念在论文建模…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...