嵌入式Linux多任务编程 进程 管道 命名管道

进程

  • 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程,也是操作系统执行资源分配和保护的基本单位。
  • 程序的一次执行就是一个进程
  • 一个程序可以派生多个进程
  • 多个不同程序运行的时候,也会有多个相对应的进程与其相互对应
  • 进程是动态的,有始有终,有自己的生命周期,有进程状态的变化

程序与进程的区别

  • 程序是静止的,无生命的,进程是活动的
  • 程序是可以脱离机器长期存在,而进程是执行了的程序
  • 程序不具备并发性,不占据系统的资源,进程则相反,具备并发性、会占据内存空间,并且会受到其他进程的制约和影响
  • 一个程序对应很多的进程

进程的状态

  • 运行状态
  • 就绪状态 缺少cpu
  • 等待状态 缺少IO资源,等待

相关命令

  • 使用命令 ps -ax 查看进程的相关状态;比如进程号 、 进程的状态、

进程树的形成

  • 计算机启动之后,BIOS从磁盘引导扇区加载系统引导程序,它将Linux系统装入内存,并且跳到内核处开始执行,Linux内核就执行初始化工作:初始化硬件、初始化内部数据结构、建立进程0
  • 进程0创建进程1,进程1是以后所有创建进程的祖先,它负责初始化所有的用户进程。进程1创建shell,shell进程显示提示符,等待命令的输入
  • init进程ID为1,通常是init进程,在自检过程结束的时候由内核调用
  • init进程不会终止
  • init进程是一个普通的用户进程(与交换进程不同,他不是内核中的系统进程,但是它以超级用户特权执行)

进程的创建

  • 任何进程的创建,都是基于现有的进程
  • 进程的创建可以使用fork 和 exec
  • fork 视为新的进程分配响应的数据结构,并且将父进程的相应上下文信息复制过来
  • exec 将可执行文件的正文和数据转入内存替代先前的内容(从父进程复制过来的数据),并开始执行正文段,将当前进程替换为一个新的进程

进程的终止

  • 使用exit()
  • exit释放除了task_struct以外的所有的上下文,父进程收到子进程的终结信号之后,释放子进程的task_struct
  • vfork调用之后,将立即调用exec,这样就不需要拷贝父进程的所有的页表,因此比fork快
  • pid_t fork(void);
  • pid_t vfor(void);
  • 头文件 unistd.h

fork系统调用

  • 当fork函数调用成功时,对父进程返回子进程的PID,对子进程返回0
  • 调用失败的时候,父进程返回-1,并没有子进程的创建
  • fork函数返回 两个参数,分别给父进程和子进程
pid_t new_pid;
new_pid = fork();
switch(new_pid){case -1://Error!break;case 0://Child processbreak;default://parent processbreak;
}

exec系统调用

  • exec是用来执行一个可执行文件来代替当前进程的执行镜像
  • int execl(const char * path,const char * arg, ...)
  • int execlp(const char * file,const char * arg, ...)
  • int execle(const char *path, const char * arg,...,const char *envp[])
  •  int execv(const char *path,const char * argv[])
  • int execve(const char * filename,char * const argv[],char * const envp[])
  • int execvp(const char *file,char * const argv[])

函数的原型

  • int execve(const char * filename,char * const argv[],char * const envp[])
  • filename   执行的文件
  • argv          传递给文件的参数
  • envp         传递给文件的环境变量
  • 当参数path所指定的文件替换原进程的执行镜像之后,文件的path开始执行,参数argv和envp便传递给进程
  • l 表示list
  • v表示vector
  • e 可以传递新进程环境变量 execle execve
  • p 可执行文件查找方式为文件的名字 execlp execvp
    char* envp[] = {"PATH = /tmp","User = lei","STATUS = testing", nullptr};char* argv_execv[] = {"echo","executed by execv", nullptr};char* argv_execvp[] = {"echo","executed by execvp", nullptr};char* argv_execve[] = {"env", nullptr};if (execl("/bin/echo","echo","executed by execl", nullptr)<0)perror("Err on execl");if (execlp("echo","echo","executed by execlp", nullptr)<0)perror("Err on execlp");if(execle("/user/bin/env","env", nullptr,envp)<0)perror("Err on execle");if (execv("/bin/echo",argv_execv)<0)perror("Err on execv");if (execvp("echo",argv_execvp))perror("Err on execvp");if(execve("/user/bin/ebv",argv_execve,envp)<0)perror("Err on execve");

函数

  •  头文件 <sys/types.h> <unistd.h>
  • pid_t getpid(void);返回调用进程的进程ID
  • pid_t getppid(void);但会调用进程的父进程ID
  • uid_t getuid(void);返回调用进程的实际用户ID
  • uid_t geteuid(void);返回进程的有效用户ID
  • gid_t getgid(void);返回进程的实际组ID
  • gid_t getegit(void);调用进程的有效组ID
#include <iostream>
#include <sys/types.h>
#include <unistd.h>int main(){pid_t cld_pid;cld_pid = fork();if (cld_pid == 0){std::cout << "This is child process.\n" << std::endl;printf("My PID(child) is %d\n",getpid());printf("My child PID is %d\n",cld_pid );}else{std::cout << "This is parent process.\n" << std::endl;printf("My PID(parent) is %d\n",getpid());printf("My child PID is %d\n",cld_pid );}return 0;
}

 exit系统调用

  • _exit 直接结束进程,清除其内存使用空间,并且清除其在内核中的数据结构
  • exit 函数在调用之前会检查文件的打开情况,把文件的缓存区的内容写会文件中,比如调用printf()函数

wait系统调用

  • wait函数 用于使父进程阻塞,直到一个进程结束或者该进程收到一个指定信号为止
  • 调用wait或者waitpid的进程可能会:
  • 阻塞:如果其所有的进程还在运行
  • 带子进程的终止状态立即返回(如果一个子进程已经终止,正等待父进程存取其终止状态)
  • 出错立即返回(如果没有任何子进程)
  • pid_t wait(int *status);  status返回子进程退出时的状态信息
  • pid_t waitpid(pid_t pid,int *status,int options);//等待指定的进程id
  • 头文件 <sys/types.h> 和 <sys/wait.h>
  • 两个函数返回数值:如果成功返回子进程的ID号,如果出现问题,返回-1

wait和waitpid函数的区别

  • 在一个子进程终止之前,wait使其调用者阻塞,而waitpid有一个选项,可以不阻塞调用者
  • waitpid并不等待第一个终止的子进程,他有若干个选择项,可以控制他所等待的特定进程
  • 实际上,wait函数是waitpid的一个特例

守护进程

  • 创建子进程,然后父进程退出
  • 在子进程中创建新的会话 setsid();
  • 改变目录为根目录 chdir("/");
  • 重设文件的权限掩码umask(0);
  • 关闭文件描述符 for(int i = 0;i < MAXFILE; i++){close(i);}
  • 守护进程的工作 while(1){}
#include <iostream>
#include <unistd.h>
#include <ftw.h>
#include <fcntl.h>int main(){pid_t pc;char *buf = "This is a Daemon\n";int len = strlen(buf);pc = fork();if (pc < 0){printf("Error fork!\n");exit(-1);} else if (pc > 0){exit(0);}setsid();//在子进程中创建新的会话chdir("/");//改变目录为根目录umask(0);//重设文件的权限掩码for (int i = 0; i < 65535; ++i) {close(i);}int fd;while (1){if (fd = open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600) < 0){perror("open");exit(1);}write(fd,buf,len+1);close(fd);sleep(10);}return 0;
}

sleep函数

  • 函数使用sleep用来指定进程挂起来的指定的秒数。该函数的调用格式如下
  • unsigned int sleep(unsigned int seconds);
  • 头文件 unistd.h

进程间通信

  • 数据传输:一个进程将 数据 发送给另外一个进程,数据大小一般是一个字节到几兆字节之间
  • 共享数据:多个进程之间操作共享数据,一个进程对共享数据的修改,另外的进程可以看到
  • 通知事件:一个进程向另外一个进程发送消息,通知它发生了某件事情。(如:子进程终止,通知父进程)
  • 资源共享:多个进程之间共享相同的资源,需要内核提供 锁 和 同步机制
  • 进程控制:有些进程完全控制另一个进程的执行(如Debug),这个时候,进程会拦截另外一个进程所有的陷入(陷入内核)和异常,并且及时知道他的状态改变
  • 进程间通信 (IPC)
  • Linux进程间通信 包括Unix进程间通信、Socket进程间通信、POSIX进程间通信、System V进程间通信
  • Unix进程间通信 -> 管道 FIFO 信号
  • System V进程间通信 -> System V消息队列  System V信号灯  System V共享内存
  • POSIX进程间通信 -> posix消息队列 posix信号灯  posix共享内存

现在的linux使用的进程间通信方式

  • 管道(pipe) 和 有名管道(FIFO)
  • 信号(signal):比较复杂的通信方式,用于通知其余进程,信号可以用于进程之间通信外,信号还可以发送信号给进程本身。
  • 消息队列:消息的链接表,包括posix消息队列和system V消息队列;有权限的进程可以读写消息队列;克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺陷
  • 共享内存:多个进程访问同一块内存空间,是最快的IPC方式,往往结合信号量来实现进程间同步以及互斥
  • 信号量 (使用不多)
  • 套接字(socket)  (网络)

管道和有名管道的区别

  • 管道:具有亲缘关系的进程间通信,需要通信双方的进程有共同的祖先进程
  • 有名管道:允许无亲缘关系的管道之间通信,在文件系统中有对应的文件名字;有名管道通过命令 mkfifo或系统调用mkfifo来创建

具体使用

管道

  • linux命令允许重定向,重定向就是管道 例如 ls > 1.txt
  • 管道是单向的、先进先出的,无结构的、固定大小的字节流,他把一个进程的标准输出和另外一个进程的标准输入连接在一起
  • 写进程在管道的末尾输入数据,读进程在管道的首端读取数据。数据被读出后会从管道中移除,其他进程对此不可见了
  • 管道提供了简单的流控制机制。进程试图读取空的管道时,在有数据填充管道之前会处于阻塞状态;同理,管道数据已满时,未有读进程读取数据,写进程往管道里面写入数据会处于阻塞状态
  • 管道用于进程之间通信
  • 使用系统调用pipe() 函数,创建一个简单的管道,只需接受一个参数,也就是一个包括两个整数的数组。
  • 如果系统调用成功,此数组将包括管道使用的两个文件描述符
  • 创建一个管道之后,一般情况下进程将会产生一个新的进程
  • 系统调用pip()  原型:int pipe(int fd[2])
  • 返回值:成功返回0 ;失败返回 -1
  • errno = EMFILE  没有空闲的文件描述符
  • errno = ENFILE  系统文件表已满
  • errno = EFAULT  fd数组无效

代码

#include <stdio.h>
#include <unistd.h>int main(void)
{int pipe_fd[2];if(pipe(pipe_fd) < 0){printf("pipe create error!\n");return -1;} else{printf("pipe create success!\n");}close(pipe_fd[0]);close(pipe_fd[1]);return 0;
}
  • 先创建一个管道 再创建一个子进程 

父子进程之间通信  父进程写入;子进程读入数据

  • 当读到10的时候,结束进程
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main(void)
{int pipe_fd[2];pid_t pid;char buf[2]={0};//在创建子进程之前创建管道if(pipe(pipe_fd) < 0){printf("pipe create error!\n");_exit(-1);} else{printf("pipe create success!\n");printf("pipe_fd[0] = %d,pipe_fd[1] = %d",pipe_fd[0],pipe_fd[1]);}pid = fork();//创建子进程//子进程执行的代码if (pid == 0){close(pipe_fd[1]);while (1){if (read(pipe_fd[0],buf,1) > 0){
//                if (buf[0] % 3 == 0 && buf[0] != 0)printf("%d\n",buf[0]);if (buf[0] == 10)_exit(0);}}close(pipe_fd[0]);} else{//父进程执行的代码close(pipe_fd[0]);for (buf[0]=0;buf[0]<=10;buf[0]++) {write(pipe_fd[1],buf,1);}close(pipe_fd[1]);wait(nullptr);}return 0;
}

上面这个例子 感觉有问题 

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <cstring>int main(){int pipe_fd[2];if (pipe(pipe_fd) < 0){printf("pipe create error!\n");_exit(-1);return -1;} else{printf("pipe create success!\n");printf("pipe_fd[0] = %d,pipe_fd[1] = %d",pipe_fd[0],pipe_fd[1]);}pid_t pid = fork();
//    char buf[2] = {0};char buf[100] ={"Hello world"};int len = strlen(buf);if (pid == 0){close(pipe_fd[1]);while(1){if (read(pipe_fd[0],buf,len) > 0){printf("%s\n",buf);}}close(pipe_fd[0]);} else{//父进程执行此段代码close(pipe_fd[0]);for (int i = 0;i<10;i++){write(pipe_fd[1], buf, len);}close(pipe_fd[1]);wait(nullptr);}return 0;
}

 简单修改如下

 

  •  通过打开两根管道,实现一个双向的管道,但是需要在子进程中正确的设置文件的描述符号
  • 必须在fork之前使用pipe(),否则子进程将不会继承文件的描述符
  • 使用半双工管道的时候,任何关联的进程都需要共享一个相关的祖先进程。因为管道存储在系统内核中,不继承祖先将无法寻址,有名管道就不会出现这个问题

代码

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main(void)
{int pipe_fd[2];int pipe_fd1[2];pid_t pid;char buf_r[100]={0};char * p_wbuf = nullptr;int r_num;//在创建子进程之前创建管道if(pipe(pipe_fd) < 0){printf("pipe create error!\n");_exit(-1);}if(pipe(pipe_fd1) < 0){printf("pipe create error!\n");_exit(-1);}printf("pipe create success!\n");
//    printf("pipe_fd[0] = %d,pipe_fd[1] = %d",pipe_fd[0],pipe_fd[1]);
//    printf("pipe_fd1[0] = %d,pipe_fd1[1] = %d",pipe_fd1[0],pipe_fd1[1]);pid = fork();//创建子进程//子进程执行的代码if (pid == 0){printf("******子进程******\n");//read pipeclose(pipe_fd[1]);r_num = read(pipe_fd[0],buf_r,100);if (r_num > 0){printf("children r_num = %d, pipe is: %s\n",r_num,buf_r);}close(pipe_fd[0]);//write pipeclose(pipe_fd1[0]);if (write(pipe_fd1[1],"ByeBye!",7)!=-1){printf("children process write ByeBye! success!\n");}close(pipe_fd1[1]);printf("children process exit!\n");_exit(0);} else if (pid > 0){printf("******父进程******\n");//write pipeclose(pipe_fd[0]);if (write(pipe_fd[1],"Hello!",6) !=-1){printf("father process write Hello! success!\n");}close(pipe_fd[1]);//read processclose(pipe_fd1[1]);r_num = read(pipe_fd1[0],buf_r,100);if (r_num > 0){printf("father r_num = %d, pipe is: %s\n",r_num,buf_r);}close(pipe_fd1[0]);wait(nullptr);printf("father process exit!\n");_exit(0);}return 0;
}
  •  父进程 给 子进程 传输 Hello!;接收输出子进程的 ByeBye!
  • 子进程 给 父进程 传输 ByeBye!;接收输出父进程的 Hello!
  • 子进程退出,然后父进程退出
  • r_num 为读取的数据长度

命名管道

  • 作为一个特殊的设备文件而存在
  • 适用于无血缘关系的进程之间通信
  • 即使进程之间不再需要管道,但是命名管道仍然继续保存在文件系统中,便于以后使用
  • 使用函数 int mkfifo(const char * pathname,mode_t mode)
  • 函数说明:mkfifo()会依参数pathname 建立特殊的FIFO 文件, 该文件必须不存在, 而参数mode 为该文件的权限 (mode%~umask), 因此umask 值也会影响到FIFO 文件的权限. Mkfifo()建立的FIFO 文件其他进程都可以用读写一般文件的方式存取. 当使用open()来打开FIFO 文件时, O_NONBLOCK 旗标会有影响:
  • 头文件:#include <sys/types.h>   #include <sys/stat.h>
  • 1. 当使用O_NONBLOCK 旗标时, 打开FIFO 文件来读取的操作会立刻返回, 但是若还没有其他进程打开FIFO 文件来读取, 则写入的操作会返回ENXIO 错误代码.
  • 2. 没有使用O_NONBLOCK 旗标时, 打开FIFO 来读取的操作会等到其他进程打开FIFO 文件来写入才正常返回. 同样地, 打开FIFO 文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回.
  • 返回值:若成功则返回0, 否则返回-1, 错误原因存于errno 中
  • 使用ls -l查看管道文件 显示p开头
  • 普通文件 是一个 - 

错误代码:

  • 1、EACCESS 参数pathname 所指定的目录路径无可执行的权限
  • 2、EEXIST 参数pathname 所指定的文件已存在.
  • 3、ENAMETOOLONG 参数pathname 的路径名称太长.
  • 4、ENOENT 参数pathname 包含的目录不存在
  • 5、ENOSPC 文件系统的剩余空间不足
  • 6、ENOTDIR 参数pathname 路径中的目录存在但却非真正的目录.
  • 7、EROFS 参数pathname 指定的文件存在于只读文件系统内.

注意事项

  • 打开FIFO,使用非阻塞标志(O_NONBLOCK)产生以下的影响
  • 如果未说明O_NONBLOCK,只读打开会要阻塞某个写进程打开此FIFO;类似,只写打开要阻塞某个读进程打开此FIFO;读写互斥
  • 如果指定了O_NONBLOCK,则只读打开立即返回,但是如果没有进程为了读而打开一个FIFO,那么只写打开将出错返回,其errno是ENXIO
  • 类似管道,若写一个尚无进程为读而打开的FIFO,则产生信号为SIGPIPE;若某个FIFO最后一个写进程关闭了该FIFO,则将为该FIFO的读进程产生一个文件结束标志

参考链接

  • Linux进程描述符task_struct结构体详解--Linux进程的管理与调度(一)
  • Linux 系统启动过程
  • Linux系统启动流程详解
  • fork和exec的区别
  • Linux中fork,vfork和clone详解(区别与联系)
  • C语言vfork()函数:建立新的进程
  • linux系统编程之进程(五):exec系列函数(execl,execlp,execle,execv,execvp)使用
  • C语言waitpid()函数:中断(结束)进程函数(等待子进程中断或
  • linux守护进程详解及创建,daemon()使用
  • linux系统的7种运行级别
  • SGX的内部组件概述(一)找一个好的工作,为自己活
  • C语言mkfifo()函数:建立具名管道
  • linux驱动重要头文件!!!
  • errno头文件

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

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

相关文章

英语口语-文章朗读Week10 Thursday

英语文章 There are many customs and traditions in Chinese civilization. Here, we will talk about the development of the way people greet each other: In ancient times, people had to kneel to those who were superior to them. This custom remained until the …

Linux进程之间通信 信号

2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出&#xff0c;用于通知前台进程组终止进程。 3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 15)…

Linux进程之间通信 消息队列

使用命令 ipcs -q 查看对应的消息队列代码 文件接收者 #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <string> #include <signal.h> #include <wait.h> #include <sys/msg.h> #include <cstring&g…

c++面向对象高级编程 学习二 带指针的类

带指针的类&#xff0c;必须要自己写拷贝构造和赋值构造 拷贝构造&#xff1a;参数和类的类型一样的构造函数 赋值构造&#xff1a;重写操作符&#xff0c;且其参数和类的类型一样 class String { public: String(const char* cstr 0); String(const String& str); Strin…

英语口语 week11 Tuesday

英语文章 It was a cold and gloomy winter afternoon, people with their chilled hands tucked into their pockets or hidden in their sleeves. Fred was in a depressed mood, just like the weather,for he failed to get any award in the debate competition When he …

进程之间通信 共享内存

命令 ipcs 命令查看共享内存、消息队列、管道等相关信息ipcs -m 查看共享内存的信息代码 创建共享内存共享内存 关联 进程分离共享内存删除共享内存 #include <sys/shm.h> #include <iostream>#define BUF_SIZE 1024int main() {int share_id 0;//创建共享内存i…

c++面向对象高级编程 学习三 堆、栈和内存泄漏

栈&#xff0c;是存在于某作用域的一块内存空间。在函数体内声明的任何变量&#xff0c;其所使用的内存空间均来自于栈。 堆&#xff0c;是指由操作系统提供的一块global内存空间&#xff0c;程序可动态分配获得若干内存空间块。 new操作符生成的对象所占用的内存空间即是从堆中…

clion编写C++ 使用多线程时候,CMakeLists.txt书写,引用-pthread

添加如下一行 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") 具体的例子 cmake_minimum_required(VERSION 3.17) project(mutex_learn)set(CMAKE_CXX_STANDARD 14)set(BOOST_ROOT "/usr/local/include/boost") #添加头文件搜索路径 include_direc…

c++面向对象高级编程 学习四 静态、类模板、函数模板

静态static&#xff1a;静态数据和静态函数&#xff0c;在内存中只有一份&#xff0c;不会随着创建对象的数目的增加而增加 static数据&#xff1a;比如银行的account类中&#xff0c;账户名是普通数据&#xff0c;100个对象会有100个账户名&#xff0c;但利率都是相同的&#…

线程的编程

完整代码 #include <sys/shm.h> #include <iostream> #include <unistd.h> #include <pthread.h>void * child1(void *arg){pthread_t tid pthread_self();printf("1 thread %lu \n",tid);}int main(int argc,char* argv[]) {int result{…

英语口语 week11 Friday

英语文章 I very much like simplicity in life. For me, college is far more than a place to improve my intellectual abilities Every weekend, I usually have a walk along the way to the front gate of Mount Qingcheng, enjoying the intense aromas of flowers on …

c++面向对象高级编程 学习五 组合、委托与继承

组合 composition 表示has a queue类中有一个deque容器&#xff0c;这种关系叫做 组合 queue中的六个函数都是调用c的函数完成的 template <class T> class queue { ... protected: deque<T> c; // 底層容器 public: // 以下完全利用 c 的操作函數完成 bool empt…

英语口语 week12 WednesDay

英语文章 Chengdu, a city with a long history, has always enjoyed the reputation as " The Land of Abundance" . It has been noted as one of the most livable cities in China, partly resulting from its favorable natural conditions and wealthy produc…

c++面向对象高级编程 学习六 虚函数

虚函数&#xff1a;在成员函数前面加上virtual&#xff0c;函数就变成了虚函数 继承函数&#xff1a;子类可以调用父类的函数&#xff0c;叫做继承了函数&#xff0c;即函数的调用权 三种函数&#xff1a; non-virtual 函数&#xff1a; 你不希望 derived class 重新定义 (ov…

C++ 数据结构 线性链表

#pragma once 减少头文件组合&#xff0c;降低编译出错的概率作用等效于 #ifndef FUNC_H #define FUNC_H代码主体#endif 线性表的定义 排队问题 简单的线性表 (物理 或者逻辑结构)1&#xff0c;数组2&#xff0c;链表线性表相关操作&#xff1a;1&#xff0c;线性表初始化2&a…

英语口语 week12 Thursday

英语文章 As the pace of life quickens with technological advancements, people are occupied by all kinds of trivial matters. They seem forever on the go. There’s no difficulty in imagining that the hustle and bustle of everyday life can make us lose focus…

H.264/AVC视频编解码技术详解 第一章 视频信息与压缩编码

H.264/AVC视频编解码技术详解系列笔记 是对 H.264/AVC视频编解码技术详解 课程的学习 文章目录人与世界的交互视频信号的表示方法视频压缩编码视频信息为什么可以被压缩&#xff1f;视频压缩编码的分类&#xff1a;视频压缩编码的基本技术人与世界的交互 从远古时代开始&#…

英语口语 week13 Monday

英语文章 Competitions between businesses can be very aggressive in contemporary society. However, the competition for talented personnel is thought to be the key to business competition. Wise employers consider their employees as the company’s core asset…

文件系统的由来

启蒙篇 文件的由来 磁盘上保存的是一对十六进制的数据&#xff0c;如何切分数据形成不同的文件&#xff0c;也就是如何确定一个文件的起始和终止位置&#xff1f;将相关数据打包在一起形成一个文件&#xff0c;比如从什么位置开始到什么位置结束&#xff0c;是一张图片、一段…

英语口语 week13 Wednesday

英语文章 Despite his extraordinary success in writing fairy tales,Hans Christian Andersen preferred to living in a way of simplicity and frugality. He often wore an old hat when he went out. One day, a well-dressed man stopped Andersen on the street, inte…