linux系统编程重点复习--进程的控制

news2024/9/23 3:32:39

目录

1 复习目标

2 进程相关概念

2.2 并行和并发

2.3 PCB-进程控制块 

2.4 进程状态(面试考)

 3 创建进程

3.2 ps命令和kill命令

3.3 getpid/getppid

3.4 练习题

 

4 exec函数族

        4.1 函数作用和函数介绍

4.1.1 execl函数

4.1.2 execlp函数

4.2 exec函数族原理介绍

4.3 exec函数练习

5 进程回收

5.1 为什么要进行进程资源的回收

5.2 孤儿进程

5.3 僵尸进程

5.4 进程回收函数

5.4.1 wait函数

5.4.2waitpid函数

6 作业

6.1 作业1

6.2 作业2

7 大纲


1 复习目标

  1. 了解进程相关的概念
  2. 掌握fork/getpid/getppid函数的使用
  3. 熟练掌握ps/kill命令的使用
  4. 熟练掌握execl/execlp函数的使用
  5. 说出什么是孤儿进程什么是僵尸进程
  6. 熟练掌握wait函数的使用
  7. 熟练掌握waitpid函数的使用

2 进程相关概念

  1. 程序,是指编译好的二进制文件,在磁盘上,占用磁盘空间, 是一个静态的概念.
  2. 进程,一个启动的程序, 进程占用的是系统资源,如:物理内存,CPU,终端等,是一个动态的概念
  3. 程序 → 剧本(纸)
  4. 进程 → 戏(舞台、演员、灯光、道具...)

同一个剧本可以在多个舞台同时上演。同样,同一个程序也可以加载为不同的进程(彼此之间互不影响)

2.2 并行和并发

  1. 并发,在一个时间段内, 是在同一个cpu上, 同时运行多个程序。

如:若将CPU的1S的时间分成1000个时间片,每个进程执行完一个时间片必须无条件让出CPU的使用权,这样1S中就可以执行1000个进程。

 

 

 

  1. 并行性指两个或两个以上的程序在同一时刻发生(需要有多颗)。

 

2.3 PCB-进程控制块 

每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。

/usr/src/linux-headers-4.4.0-96/include/linux/sched.h文件的1390行处可以查看struct task_struct 结构体定义。其内部成员有很多,我们重点掌握以下部分即可:

  • 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。
  • 进程的状态,有就绪、运行、挂起、停止等状态。
  • 进程切换时需要保存和恢复的一些CPU寄存器。
  • 描述虚拟地址空间的信息。
  • 描述控制终端的信息。
  • 当前工作目录(Current Working Directory)。getcwd --pwd
  • umask掩码。
  • 文件描述符表,包含很多指向file结构体的指针。
  • 和信号相关的信息
  • 用户id和组id。
  • 会话(Session)和进程组。
  • 进程可以使用的资源上限(Resource Limit)。

        ulimit -a

2.4 进程状态(面试考)

  • 进程基本的状态有5种。分别为初始态,就绪态,运行态,挂起态与终止态。其中初始态为进程准备阶段,常与就绪态结合来看。

 3 创建进程

        

3.1 fork函数

函数作用:创建子进程

原型: pid_t fork(void);

函数参数:无

返回值:调用成功:父进程返回子进程的PID,子进程返回0;

        调用失败:返回-1,设置errno值。

 fork函数代码片段实例:

 

  • fork函数总结

fork函数的返回值?

 父进程返回子进程的PID,是一个大于0数;

 子进程返回0;

特别需要注意的是:不是fork函数在一个进程中返回2个值,而是在父子进程各自返回一个值。

子进程创建成功后,代码的执行位置?

   父进程执行到什么位置,子进程就从哪里执行

►如何区分父子进程

通过fork函数的返回值

►父子进程的执行顺序

  不一定,哪个进程先抢到CPU,哪个进程就先执行

3.2 ps命令和kill命令

  1. ps aux | grep "xxx"
  2. ps ajx | grep "xxx"
  • -a:(all)当前系统所有用户的进程
  • -u:查看进程所有者及其他一些信息
  • -x:显示没有控制终端的进程 -- 不能与用户进行交互的进程【输入、输出】
  • -j: 列出与作业控制相关的信息
  1. kill -l 查看系统有哪些信号
  2. kill -9 pid 杀死某个线程

3.3 getpid/getppid

getpid - 得到当前进程的PID

pid_t getpid(void);

getppid - 得到当前进程的父进程的PID

pid_t getppid(void);

//fork函数测试
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	printf("before fork, pid:[%d]\n", getpid());
	//创建子进程
	//pid_t fork(void);
	pid_t pid = fork();
	if(pid<0) //fork失败的情况
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)//父进程
	{
		printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
		//sleep(1);
	}
	else if(pid==0) //子进程
	{
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
	}
	
	printf("after fork, pid:[%d]\n", getpid());

	return 0;
}

3.4 练习题

1编写程序,循环创建多个子进程,要求如下:

多个子进程是兄弟关系。

判断子进程是第几个子进程

画图讲解创建多个子进程遇到的问题

注意:若让多个子进程都是兄弟进程,必须不能让子进程再去创建新的子进程。

//fork函数测试
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int g_var = 99;

int main()
{
	//创建子进程
	pid_t pid = fork();
	if(pid<0) //fork失败的情况
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)//父进程
	{
		printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
		g_var++;
		printf("[%p]", &g_var);
	}
	else if(pid==0) //子进程
	{
		sleep(1); //为了避免父进程还没有执行, 子进程已经结束了
		printf("[%p]", &g_var);
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
		printf("child: g_var==[%d]\n", g_var);
	}
	
	return 0;
}

2.编写程序,测试父子进程是否能够共享全局变量

重点通过这个案例讲解读时共享,写时复制

 

//循环创建n个子进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	int i = 0;
	for(i=0; i<3; i++)
	{
		//创建子进程
		pid_t pid = fork();
		if(pid<0) //fork失败的情况
		{
			perror("fork error");
			return -1;
		}
		else if(pid>0)//父进程
		{
			printf("father: pid==[%d], fpid==[%d]\n", getpid(),getppid());
			//sleep(1);
		}
		else if(pid==0) //子进程
		{
			printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
			break;
		}
	}

	//第1个子进程
	if(i==0)
	{
		printf("[%d]--[%d]: child\n", i, getpid());	
	}

	//第2个子进程
	if(i==1)
	{
		printf("[%d]--[%d]: child\n", i, getpid());	
	}
	//第3个子进程
	if(i==2)
	{
		printf("[%d]--[%d]: child\n", i, getpid());	
	}
	//父进程
	if(i==3)
	{
		printf("[%d]--[%d]: child\n", i, getpid());	
	}
	sleep(10);

	return 0;
}

4 exec函数族

        4.1 函数作用和函数介绍

  有的时候需要在一个进程里面执行其他的命令或者是用户自定义的应用程序,此时就用到了exec函数族当中的函数。使用方法一般都是在父进程里面调用fork创建处子进程,然后在子进程里面调用exec函数。

4.1.1 execl函数

函数原型: int execl(const char *path, const char *arg, ... /* (char  *) NULL */);

参数介绍:

  • path: 要执行的程序的绝对路径
  • 变参arg: 要执行的程序的需要的参数
  • arg:占位,通常写应用程序的名字
  • arg后面的: 命令的参数
  • 参数写完之后: NULL

返回值:若是成功,则不返回,不会再执行exec函数后面的代码;若是失败,会执行execl后面的代码,可以用perror打印错误原因。

execl函数一般执行自己写的程序。

4.1.2 execlp函数

函数原型: int execlp(const char *file, const char *arg, .../* (char  *) NULL */);

参数介绍:

  • file: 执行命令的名字, 根据PATH环境变量来搜索该命令
  • arg:占位
  • arg后面的: 命令的参数
  • 参数写完之后: NULL

返回值:若是成功,则不返回,不会再执行exec函数后面的代码;若是失败,会执行exec后面的代码,可以用perror打印错误原因。

execlp函数一般是执行系统自带的程序或者是命令.

4.2 exec函数族原理介绍

exec族函数的实现原理图:

 如:execlp(“ls”, “ls”, “-l”, NULL)

 

总结:

exec函数是用一个新程序替换了当前进程的代码段、数据段、堆和栈;原有的进程空间没有发生变化,并没有创建新的进程,进程PID没有发生变化。

4.3 exec函数练习

  1. 使用execl函数执行一个用户自定义的应用程序
  2. 使用execlp函数执行一个linux系统命令

注意:当execl和execlp函数执行成功后,不返回,并且不会执行execl后面的代码逻辑,原因是调用execl函数成功以后,exec函数指定的代码段已经将原有的代码段替换了。

5 进程回收

5.1 为什么要进行进程资源的回收

   当一个进程退出之后,进程能够回收自己的用户区的资源,但是不能回收内核空间的PCB资源,必须由它的父进程调用wait或者waitpid函数完成对子进程的回收,避免造成系统资源的浪费。

5.2 孤儿进程

  1. 孤儿进程的概念:

若子进程的父进程已经死掉,而子进程还存活着,这个进程就成了孤儿进程。

  1. 为了保证每个进程都有一个父进程,孤儿进程会被init进程领养,init进程成为了孤儿进程的养父进程,当孤儿进程退出之后,由init进程完成对孤儿进程的回收。
  2. 模拟孤儿进程的案例

编写模拟孤儿进程的代码讲解孤儿进程,验证孤儿进程的父进程是否由原来的父进程变成了init进程。

//孤儿进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	//创建子进程
	pid_t pid = fork();
	if(pid<0) //fork失败的情况
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)//父进程
	{
		sleep(5);
		printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
	}
	else if(pid==0) //子进程
	{
		
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
		sleep(20);
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
	}
	

	return 0;
}

5.3 僵尸进程

  1. 僵尸进程的概念:

若子进程死了,父进程还活着, 但是父进程没有调用wait或waitpid函数完成对子进程的回收,则该子进程就成了僵尸进程。

        如何解决僵尸进程

  • 由于僵尸进程是一个已经死亡的进程,所以不能使用kill命令将其杀死
  • 通过杀死其父进程的方法可以消除僵尸进程。

杀死其父进程后,这个僵尸进程会被init进程领养,由init进程完成对僵尸进程的回收。

  1. 模拟僵尸进程的案例

编写模拟僵尸进程的代码讲解僵尸进程, 验证若子进程先于父进程退出, 而父进程没有调用wait或者waitpid函数进行回收, 从而使子进程成为了僵尸进程.

//僵尸进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	//创建子进程
	pid_t pid = fork();
	if(pid<0) //fork失败的情况
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)//父进程
	{
		sleep(100);
		printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
	}
	else if(pid==0) //子进程
	{
		
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
	}
	
	return 0;
}

5.4 进程回收函数

5.4.1 wait函数

  • 函数原型:

pid_t wait(int *status);

  • 函数作用:
  • 阻塞并等待子进程退出
  • 回收子进程残留资源
  • 获取子进程结束状态(退出原因)
  • 返回值:
  • 成功:清理掉的子进程ID;
  • 失败:-1 (没有子进程)
  • status参数:子进程的退出状态 -- 传出参数
  • WIFEXITED(status):为非0         进程正常结束

                WEXITSTATUS(status):获取进程退出状态

  • WIFSIGNALED(status):为非0  进程异常终止

                WTERMSIG(status):取得进程终止的信号编号。

  wait函数练习

使用wait函数完成父进程对子进程的回收。

//父进程调用wait函数完成对子进程的回收
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
	//创建子进程
	pid_t pid = fork();
	if(pid<0) //fork失败的情况
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)//父进程
	{
		printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
		int status;
		pid_t wpid = wait(&status);
		printf("wpid==[%d]\n", wpid);
		if(WIFEXITED(status)) //正常退出
		{
			printf("child normal exit, status==[%d]\n", WEXITSTATUS(status));
		}
		else if(WIFSIGNALED(status)) //被信号杀死
		{
			printf("child killed by signal, signo==[%d]\n", WTERMSIG(status));
		}
		
	}
	else if(pid==0) //子进程
	{
		
		printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
		sleep(20);
		return 9;
	}

	return 0;
}

 

5.4.2waitpid函数

  • 函数原型:

pid_t waitpid(pid_t pid, int *status, in options);

  • 函数作用

同wait函数

  • 函数参数

参数:

pid

pid = -1 等待任一子进程。与wait等效。

pid > 0 等待其进程ID与pid相等的子进程。

pid = 0 等待进程组ID与目前进程相同的任何子进程,也就是说任何和调用

waitpid()函数的进程在同一个进程组的进程。

pid < -1 等待其组ID等于pid的绝对值的任一子进程。(适用于子进程在其他组的情况)

status: 子进程的退出状态,用法同wait函数。

options:设置为WNOHANG,函数非阻塞,设置为0,函数阻塞。

  • 函数返回值

>0:返回回收掉的子进程ID;

-1:无子进程

=0:参3为WNOHANG,且子进程正在运行。

waitpid函数练习

使用waitpid函数完成对子进程的回收

6 作业

6.1 作业1

测试父子进程之间是否共享文件

6.2 作业2

父进程fork三个子进程:

其中一个调用ps命令;

一个调用自定义应用程序;

一个调用会出现段错误的程序。

父进程回收三个子进程(waitpid),并且打印三个子进程的退出状态。

 

=== 段错误 ===

1>. 访问了非法内存

2>. 访问了不可写的区域进行写操作

3>. 栈空间溢出

char* p = “hello,world”        

p0=a’;

7 大纲

程序和进程的概念:
    程序: 是编译好的二进制文件, 存放在磁盘上, 占用的是磁盘空间, 是一个静态的概念.
    进程: 一个启动的程序, 需要占用系统资源: 如 内存, cpu 终端 等
    剧本--->程序
    进程--->唱戏(舞台, 灯光, 道具, 人等资源)
    同一个程序可以在多个终端执行, 类似与同一台戏可以在多个舞台演出.
    没启动一个程序都会有一个进程PID, 即使是相同的程序多次启动也会有个不同的PID.
并行和并发的概念:
    并发: 在一个时间段内, 一个CPU上, 有多个程序在执行.
    并行: 在一个时间片内, 有多个程序在执行(前提是有多个cpu)
    cpu会将一个大的时间段分成多个小的时间片, 让进程轮流使用CPU的时间片.


父子进程不能共享全局变量.

如果想在一个进程内部执行系统命令或者是应用程序, 优先应该想到如下方式:
先fork(), 然后在子进程里面执行execl拉起可执行程序或者命令.
pid = fork();
if(pid==0)
{
    execl(...);
}

execl: 一般用于执行用户自定义的应用程序.
execp: 一般用于执行系统命令

孤儿进程: 父进程先退出, 子进程就变成了孤儿进程, 此时被init进程领养,
          当孤儿进程退出之后, 就会被init进程回收.
          
僵尸进程: 子进程先退出, 父进程没有完成对子进程的回收, 此时子进程就变成了僵尸进程.
如何解决僵尸进程:
    不能使用kill -9杀死僵尸进程, 原因是僵尸进程是一个死掉的进程;
    应该使用杀死僵尸进程父进程的方法来解决僵尸进程;
    原因是: 杀死其父进程可以让init进程领养僵尸进程,最后由init进程回收僵尸进程.
    
wait函数:
    pid_t wait(int *status);
    返回值:
        >0: 回收的子进程的PID
        -1: 没有子进程
    参数:
        status: 子进程的退出状态
            if(WIFEXITED(status))
            {
                WEXITSTATUS(status)
            }
            else if(WIFSIGNALED(status))
            {
                WTERMSIG(status)
            }

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

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

相关文章

MongDB文档--架构体系

阿丹&#xff1a; 在开始学习先了解以及目标知识的架构体系。就能事半功倍。 架构体系 MongoDB的架构体系由以下几部分组成&#xff1a; 存储结构&#xff1a;MongoDB采用文档型存储结构&#xff0c;一个数据库包含多个集合&#xff0c;一个集合包含多个文档。存储形式&#…

socket编程函数

1.socket函数 socket ()打开一个网络通讯口&#xff0c;如果成功的话&#xff0c;就像 open()一样返回一个文件插述待&#xff0c;应用程序可以像读写文件一样用 read/write 在网络上收发数据&#xff0c;如socet0调用出错则返回-1。对于 IPV4,domain 参数指定为AF_INET。对于 …

端口扫描工具

什么是端口扫描 端口扫描是使用可用的网络扫描程序协议之一&#xff08;如 SNMP 扫描&#xff09;扫描网络中的所有端口的过程。端口扫描是通过尝试连接到网络中的端口来执行的&#xff0c;其状态是根据端口扫描软件从这些端口收到的响应决定的。这使管理员能够全面了解网络中…

【计算机网络】11、网络连通性:ping、traceroute、nslookup

文章目录 一、ping1.1 禁 ping 二、traceroute三、nslookup3.1 非交互模式3.2 交互模式 注意&#xff0c;测试网络连通性时&#xff0c;有的机器无法 ping 通&#xff0c;但可能 telnet 能通。不要因为无法 ping 通就放弃尝试。 一、ping 1.1 禁 ping 禁 ping 是通过忽略 IC…

【vue】vue-image-lazy图片懒加载使用与介绍【超详细+npm包源代码】

简介 当前插件是基于vue3&#xff0c;写的一个图片懒加载&#xff0c;文章最下方是npm包的源码&#xff0c;你可以自己拿去研究和修改&#xff0c;如有更好的想法可以留言&#xff0c;如果对你有帮助&#xff0c;可以点赞收藏和关注&#xff0c;谢谢。 后续会添加图片放大和切…

如何在地图上寻找峨眉山零公里的龙洞湖

爬峨眉山的需要&#xff0c;住在零公里附近。 据说这附近有个好玩的地方叫龙洞湖&#xff0c;我们住得远&#xff0c;想步行去看看。拿出地图&#xff0c;搜龙洞湖&#xff0c;尴尬了。搜不到具体位置。细想&#xff0c;人家整个村就叫龙洞村&#xff0c;地图上居然没有标识&a…

【git技巧】什么是 .gitkeep

.gitkeep 文件的作用 就是——使 Git 保留一个空文件夹&#xff01; Git 是一个文件追踪系统&#xff0c;这也导致了 Git 的设计初衷是对文件进行追踪&#xff0c;所以&#xff0c;Git 不会追踪一个空目录。 但是&#xff0c;在某些情况下&#xff0c;我们确实是需要保留一些…

AI 绘画Stable Diffusion 研究(三)sd模型种类介绍及安装使用详解

本文使用工具&#xff0c;作者:秋葉aaaki 免责声明: 工具免费提供 无任何盈利目的 大家好&#xff0c;我是风雨无阻。 今天为大家带来的是 AI 绘画Stable Diffusion 研究&#xff08;三&#xff09;sd模型种类介绍及安装使用详解。 目前&#xff0c;AI 绘画Stable Diffusion的…

<C++> 二、类和对象(下)

1.const成员函数 将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的任何成员进行修改。 class A { public:void Print() //这里隐藏了A* this指针{cout &l…

【win11+vs 2017+OpenCV4.5.5+Qt5.12配置】解决了过程中遇到的小问题

0.版本选择 由于Qt5无法与最新的vs2022兼容&#xff0c;扩展工具中一直显示不可用&#xff0c;所以将vs降级成vs2017。 在安装Qt的过程中&#xff0c;会选择安装Qt套件&#xff0c;其中就的MCVS 2017&#xff0c;说明vs2017是与qt兼容的。 当然也可以用qt creator这一原生IDE。…

测试|Junit相关内容

测试|Junit相关内容 文章目录 测试|Junit相关内容0.Junit说明1.Junit注解TestDisabledBeforeAll和AfterAllBeforeEach和AfterEach 2.Junit参数化单参数多参数&#xff08;多种/多组&#xff09;CSV获取参数&#xff08;支持多种&#xff09;CSV文件获取参数&#xff08;支持多种…

牛客网Verilog刷题——VL52

牛客网Verilog刷题——VL52 题目答案 题目 请编写一个十进制计数器模块&#xff0c;当mode信号为1&#xff0c;计数器输出信号递增&#xff0c;当mode信号为0&#xff0c;计数器输出信号递减。每次到达0&#xff0c;给出指示信号zero。模块的接口信号图如下&#xff1a; 模块的…

文心一言 VS 讯飞星火 VS chatgpt (69)-- 算法导论6.5 8题

八、HEAP-DELETE(A&#xff0c;i)操作能够将结点 i 从堆 A 中删除。对于一个包含 n个元素的堆&#xff0c;请设计一个能够在 O(lgn)时间内完成的 HEAP-DELETE 操作。 文心一言&#xff1a; 要在 O(log n) 时间内完成 HEAP-DELETE 操作&#xff0c;可以使用以下方法&#xff1…

IPsecVPN实验复现

基础配置&#xff1a; r1&#xff1a; r2&#xff1a; r3&#xff1a; AR1&#xff1a; 一 配置IKE AS 的安全协议&#xff1a; ike proposal 1 ---安全提议编号 encryption-algorithm aes-cbc-128 --- 加密算法 dh group5 ---DH算法 authentication-algorithm md5---…

一起来学算法(邻接矩阵)

前言&#xff1a; 邻接矩阵是数学和计算机科学中常用的一种表示方式&#xff0c;用来表述有向图或无向图&#xff0c;一张图由一组顶点&#xff08;或结点&#xff09;和一组表组成&#xff0c;用邻接矩阵就能表示这些顶点间存在的边的关系 1.图的概念 对于图而言&#xff0c;…

【业务功能篇61】SpringBoot项目流水线 dependencyManagement 标签整改依赖包版本漏洞问题

业务场景&#xff1a;当前我们项目引入了公司自研的一些公共框架组件&#xff0c;比如SSO单点登录jar包&#xff0c;文件上传服务jar包等公共组件&#xff0c;开发新功能&#xff0c;本地验证好之后&#xff0c;部署流水线&#xff0c;报出一些jar包版本的整改漏洞问题&#xf…

一文帮你快速理解协程使用模型

本文同步发表在个人博客上 0xforee’s blog 前言 A coroutine is an instance of suspendable computation. It is conceptually similar to a thread, in the sense that it takes a block of code to run that works concurrently with the rest of the code. However, a co…

d3dcompiler_47.dll缺失怎么修复,分享几种快速修复方法

当我们打开电脑软件或许游戏时候&#xff0c;如果电脑计算机中丢失了d3dcompiler_47.dll就会报错&#xff0c;丢失d3dcompiler_47.dll“”或许找不到d3dcompiler_47.dll等等提示。它主要用于编写和编译Direct3D 11的着色器程序&#xff0c;是Direct3D 11中非常重要的组成部分。…

FFmpeg下载安装及Windows开发环境设置

1 FFmpeg简介 FFmpeg&#xff1a;FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。项目的名称来自MPEG视频编码标准&#xff0c;前面的"FF"代表…

Java中集合容器详解:简单使用与案例分析

目录 一、概览 1.1 Collection 1. Set 2. List 3. Queue 1.2 Map 二、容器中的设计模式 迭代器模式 适配器模式 三、源码分析 ArrayList 1. 概览 2. 扩容 3. 删除元素 4. 序列化 5. Fail-Fast Vector 1. 同步 2. 扩容 3. 与 ArrayList 的比较 4. 替代方案…