4.进程相关

Linux 这4个进程相关的命令,太好用! 当您在Linux系统中管理进程时,了解一些进程监控命令是非常重要的。这些命令可以帮助您了解当前正在运行的进程以及它们的状态,从而更好地管理系统资源。 阅读详情

1.关于进程和程序的相关定义

1.1 程序的相关定义

image-20211108111353924

程序通俗来讲就是我们的源代码文件,然后里面还包含了其他的文件信息

程序入口地址:也就是 main 函数的位置

1.2 进程的相关定义

image-20211108112101092

进程需要资源:CPU ,内存

进程是一个抽象定义:它是一系列资源的集合,并不像程序是真真正正存在的

1.3 单道多道程序设计

image-20211108112219464

需要注意:

一个 CPU 一次只能执行一个程序,只不过因为CPU 切换进程时的速度非常快所以我们会以为它执行了多个程序

1.4 时间片

image-20211108112555228

进程调度策略及算法

6 种进程调度算法

  • 先来先服务

  • 最短进程优先

  • 高优先权优先调度算法

    ​ 根据进程在运行过程中是否可以被中断又分为

    • 抢占式
    • 非抢占式
  • 高响应比优先调度算法

  • 时间片轮转法

  • 多级反馈队列调度算法

1.5 并行和并发

image-20211108114808268

1.6 PCB 进程控制块

image-20211108114924962 image-20211108115315030

进程控制块又称进程描述符,可以和文件描述符结合起来

进程控制块记录的是进程的信息,他就是一个 struct 

1.6.1 如何查看 Linux 上限资源的信息

1.查看 Linux 上限资源信息

ulimit -a
image-20211108115609031

2.修改 Linux 上限资源

修改可以运行的进程资源数为 :100

ulimit -u 100 // 括号里面的参数+修改的值

1.7.进程的状态

进程分为三种状态和五种状态两个分类

三种状态分为:就绪态,阻塞态,还有运行态。五种状态分为新建态,就绪态,运行态,阻塞态和终止态。

1.三种状态及三种状态的转换过程

image-20211130102246128

就绪态(->运行):进程具备运行条件,等待系统按照一定的分配方式分配到 CPU 后就可以执行,由就绪态变为执行态。处在就绪状态的进程可能有多个,他们会形成一个队列,那个队列叫就绪队列。

阻塞态(->就绪):又称为等待 wait 或者睡眠 sleep 状态,这时进程正等待某件事情的发生,如输入输出的完成。当资源得到满足后或者数据处理完毕就会进入到就绪状态。

执行态:进程占用 CPU 在运行。

执行->阻塞:正在执⾏的进程因发⽣某等待事件⽽⽆法执⾏,则进程由执⾏状态变为阻塞状态。比如说:输入输出请求;申请主存或者外部存储设备资源;出现了一些故障或者读写错误之类的。。。

执行->就绪:正在执行的程序,因为时间片用完而暂停运行,或者在抢先式优先级调度算法系统中优先级更高的进行将其中断了。

2.五种状态

image-20211108120739534

2.进程的相关指令

image-20211108122025589

直接使用 man 可以查看指令的信息

man ps 

2.1 aux 显示进程的信息

1.查看进程信息

ps -aux
tty // 查看当前正在执行的指令

STAT:进程状态

START:进程开始的时间

TIME:进程持续的时间

COMMAND:执行的哪个命令产生的这个进程

image-20211108122520583

image-20211108122656751

2.进程的相关状态

image-20211108122750212

2.2 ajx 列出与作业控制相关的信息

ps ajx

PPID:父进程 ID

PID:进程 ID

PGID:进程可以分组,组 ID

SID:会话 Session ID ,将组再进行整合

可以将组 ID 和会话 ID 想象成学校学院班级之间的关系

image-20211108123246062

2.3 top 实时显示进程动态

top

直接在实时的窗口中输入以下指令,使用 q 退出实时显示

image-20211108123515572 image-20211108123853199

2.4 kill 杀死进程

kill 进程号
image-20211108123958673

2.4.1 kill -l 查看 kill 的信号

像 9 就是 kill 的一个信号,这个信号是一个宏代表一个操作。有时候发现 kill 不掉一些进程就可以使用信号进行相关操作

kill -l
image-20211108124351958

E.g.

bash 指令是当前控制台的控制程序(对于控制台的操作可以看做是一个进程),系统为了安全起见,使用 kill 2930 指令关闭控制台是无效的。所以就要使用 kill -9 2930 将控制台进程暂停掉

kill -9 2930
kill -SIGKILL 2930 // 直接使用宏也是可以的

image-20211108124451307

2.5 pid_t 进程号变量

关于进程号的相关函数

image-20211108125123365

getpid():得到当前进程编号

getppid():得到父亲进程编号

getpgid():得到组进程编号

3.进程创建:fork

3.1 fork 在父进程中创建子进程

在 lesson18 fork.c 中进行记录

3.1.1 API

image-20211109104740303

当父进程访问这个程序时返回的 id 是 >0 的,当子进程调用这个程序时返回的 id 是 0

3.1.2 代码

下面实现了书写一个程序,在程序中打开一个进程去执行程序中的 for 循环代码

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
using namespace std;
int main(){
  // 首先创建一个程序,在程序中创建进程,创建的进程会执行这个程序
  pid_t pid = fork(); // 创建一个新的进程
  // 判断当前是父进程还是子进程
  if(pid>1){
    printf("pid:%d\n",pid);
    printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());

  }
  if(pid==0){
    printf("i am child process,pid:%d,ppid:%d\n",getpid(),getppid());
  }
  // 创建 for 循环操作
  for(int i =0;i<100;i++){
    printf("i:%d,pid:%d\n",i,getpid());
  }
  return 0;
}

3.1.3 代码演示

从结果中可以看出,执行这个程序时需要一个进程,这个是系统帮我们开出的,然后在此进程

的基础上人为又开了个进程,这两个进程一同执行程序

** fork 调用时会有两次返回值,一次是在父进程,一次在子进程**

image-20211109112410402

image-20211109112819914

其中 3155 进程就是命令窗口进程

子进程和父进程都会执行这个程序:

这是因为父进程和子进程调用的代码是不一样的。因为父进程和子进程 id 是限制住的,导致执行的代码不一样

image-20211109113231539

3.1.4 子进程和父进程的读时共享写时拷贝(copy-on-write)

子进程是对父进程的复制,内存空间也是直接复制

image-20211109113655523

内存空间的使用情况:

因为是直接复制的虚拟空间,所以两个进程的虚拟空间中数据都是一样的,唯一不一一样的就是保存在栈空间的 pid

我们的程序会根据栈空间的值去判断应该执行哪一段程序

image-20211109113913234

写时拷贝:

写时拷贝参考资料

image-20211109115326053image-20211109115340816

内核此时并不复制整个父进程的空间,而是让父子进程共享同一个地址空间,指针指向同一个变量地址
只用在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间
	如果只对某个变量进行读取:直接读
	写:假设更改 num = 10 的数据。本来都是指向物理空间的 num10 ,当写的时候子进程开辟一个新空间向物理空间写数据

4.进程创建:GDB 实现多进程调试

在 lesson18 hello.c 中进行记录

4.1 代码

这里先创建一个进程,不同的进程会执行不同的函数。

其中父进程打印的是 i ,子进程打印的是 j

#include <stdio.h>
#include <unistd.h>
int main() {
    printf("begin\n");
    if(fork() > 0) {
        printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid()); // line 10
        int i;
        for(i = 0; i < 10; i++) {
            printf("i = %d\n", i);
            sleep(1);
        }

    } else {
        printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid()); // line
        int j;
        for(j = 0; j < 10; j++) {
            printf("j = %d\n", j);
            sleep(1);
        }
    }
    return 0;
}    

4.2使用 GDB 进行调试

image-20211109130916819

4.1 GDB 调试父进程

1.添加 GDB 调试

gcc hello.c -o hello -g // 生成 GDB 编译
gdb hello // 使用 GDB 的方式打开软件

2.添加断点

在第 10 行和第 20 行添加断点

b 10 // printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid()); 
b 20 // printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid()); 
i b // 查看断点情况
r // 执行程序
image-20211109124145827

下面使用 r 执行代码:

可以看到在执行到父进程的指令时程序停止了,接着执行子进程的程序,直到子进程执行完毕,但是发现,这时候 gdb 还能输入东西

image-20211109125808387
c // 继续执行代码

从下图发现父进程则继续执行

这里对子进程设置的断点没有执行,原因是 GDB 默认调试父进程的程序,不调试子进程产生的断点

image-20211109124923046

4.2 GDB 如何调试子进程

4.2.1 show follow-fork-mode 查看当前 GDB 调试的进程

show folllow-fork-mode
image-20211109125239226

4.2.2 show/set follow-fork-mode [parent(默认)|child] 设置 GDB 跟踪父进程还是子进程

在原有进程上调整执行的进程

set follow-fork-mode child
r // 重新运行程序
image-20211109130637857
n // 进行下一行指令操作

从下图可以看到后面再调试的都是子进程

image-20211109130736578

4.3 show/set detach-on-fork[on|off] 设置调试模式

像上面的程序,当父进行执行到断点的时候子进程还是一直执行的。这个函数可以设置另一个进程不执行

on-调试进程执行时其他进程继续执行

off-调试进程执行时其他进程不执行

show detach-on-fork // 查看调试模式
set detach-on-fork [on|off] // 设置调试模式
image-20211109132313526

4.4 查看,切换调试的进程

info inferiors // 先查看当前执行的进程
inferior +number // 然后切换执行的进程
image-20211109132748393

*指向的地方就是当前执行的继承,当时用进程切换时就可以切换到子进程,这个时候调试得就是子进程的代码

当进入到子进程的程序段后别忘了在写一个 c 程序才会继续执行

c
image-20211109132847485

进程执行完毕

5632 进程已经执行完毕,默认切换成子进程,然后继续再调试子进程

image-20211109133532651
detach inferiors +id // 跳出这个进程的 debug

脱离了 debug 之后程序就会继续执行

image-20211109134203571

5.进程创建:exec 函数族

5.1 函数族函数介绍

image-20211110103934871

5.2 虚拟空间变化

image-20211109225546843 image-20211109225833873

正是因为原函数的虚拟内存会被销毁,所以需要创建一个子进程用于执行调用函数

并且最后子进程不会再返回到父进程当中

5.3.相关调用函数

5.3.1 execl 执行可执行程序和Shell指令

1.执行自定义的某个程序

1.API

image-20211109225915052

这里传入的是文件的执行文件,而不是 C 文件

调用失败后:内核还是继续执行调用函数,调用函数最后是有返回值的。调用成功后执行的是 a.out ,这个是没有设置相应的返回值的

2.代码

#include<stdio.h>
#include<unistd.h>
int main(){
    pid_t pid = fork(); // 创建子进程
    if(pid>0){ // 执行父进程
        printf("i am parent:%d",getpid());
        sleep(1);
    }

    else if(pid==0){ // 执行子进程
        execl("hello","hello",NULL); // 第一个参数一般写可执行程序的名称,最后以 NULL 结尾
        printf("i am child im back");// 这句话不会再输出
    }
    for(int i =0;i<3;i++){ //
        printf("i=%d,pid=%d\n",i,getpid());
    }

    return 0;
}

3.代码演示

image-20211110100140290

需要注意1: 当子进程调用执行文件之后不会再返回到原有调用它的进程当中

可以看到 “i am child im back” 这句话并没有输出,说明这个进程就去执行执行程序不再返回去了

后面再执行 for 循环方法的是父进程

2.执行 shell 指令

1.如何查看系统程序保存在哪

刚才的 execl 需要传入可执行文件的路径,使用以下命令行就可以看到某个执行文件的保存地址,以 ps 指令为例

which +指令(执行文件)
E.g. :which ps

2.执行 Shell 指令

execl("/bin/ps","ps","aux",NULL); // aux 是传递的参数

可以看出执行这个文件时就相当于执行了 ps -aux

image-20211110101527844

5.3.2 execlp 执行可执行文件

1.API

image-20211110102646471

5.4函数族的调用函数命名规则

execlp 结尾是 p ;execl 结尾是 l

p(path) :按 PATH 环境变量指定的目录搜索可执行文件

所以定义 execlp 时如果不传入文件的绝对路径依旧可以通过环境变量找到该文件

但是 execl 没有 p ,所以如果调用 execl 方法不传入具体的绝对路径或者可执行文件没有和 .c 文件在一个目录下,则这个可执行文件就找不到,并且不会被执行

l(list):参数地址列表,以空指针结尾

可以看到两个方法都有 l ,并且我们传入的参数是一个字符串(参数地址列表),以NULL 结尾

下图中 execv 使用的是 v 出入的就是参数数组

image-20211110103737103

6.进程控制

6.1 进程退出

6.1.1 exit 退出进程

image-20211110105046610

C 的 exit() 标准库函数会进行函数处理操作和 IO 刷新缓冲区的操作

Linux 则不会

1.API

image-20211110111051469

2.代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
        printf("Hello\n");
        printf("world");
        _exit(0); // Linux
        //exit(0); // C
        return 0;
}

3.代码演示

(1) Linux 中的输出

可以看出没有输出 world ,这是因为 C 会将字符串保存在缓冲区中,而 \n 具有对缓冲区的刷新操作,所以Hello 会打印出来,但是 _exit() 是没有刷新缓冲区的操作的,所以这里的 world 还是保存在缓冲区内

image-20211110110252266

(2)C 标准库的输出

这里输出的 world 是因为 C 的 exit 会对缓冲区内的字符串进行刷新操作

image-20211110110901388

6.2进程相关定义

6.2.1 孤儿进程

1.解释说明

image-20211110111629453

父进程已经运行完,但是子进程还没运行完,父进程没有办法回收子进程资源,init 进程就会回收孤儿进程 ,init 的 ppid 为 1。孤儿进程没有什么危害

2.代码

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(){
        // 首先创建一个程序,在程序中创建进程,创建的进程会执行这个程序
    pid_t pid = fork(); // 创建一个新的进程
        // 判断当前是父进程还是子进程
    if(pid>1){
        printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());

    }
    if(pid==0){
         sleep(1);
        printf("i am child process,pid:%d,ppid:%d\n",getpid(),getppid());
    }
    // 创建 for 循环操作
    for(int i =0;i<3;i++){
        printf("i:%d,pid:%d\n",i,getpid());
    }
        return 0;
}

3.代码演示

image-20211110112741943

①:父进程先执行,看到其 id 和基于 bash 的 ppid

②父进程已经执行完毕,这时候父进程被其父进程 bash 回收,所以在这里出现了控制台的指令

③子进程开始执行,但是本应该调用他的父进程已经被销毁,所有由 init 去执行和销毁它,ppid 是1

6.2.2 僵尸进程

代码保地址:/home/xu/C++/lesson20 /zombie.c

1.定义

子进程的 PCB 需要由父进程释放,一个进程内核区的 PCB 没有被释放掉,残留的资源一直存放在内存中,并且不能用 kill -9 杀死。但是系统所能使用的进程号有限,导致没有办法创建新的进程,僵尸进程是有害的进程。

2.代码

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(){
    // 首先创建一个程序,在程序中创建进程,创建的进程会执行这个程序
    pid_t pid = fork(); // 创建一个新的进程
    // 判断当前是父进程还是子进程
    if(pid>1){
        printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
        while(1){
            sleep(1);
            printf("i am zombie\n");
        }

    }
    if(pid==0){
        printf("i am child process,pid:%d,ppid:%d\n",getpid(),getppid());
    }
    return 0;
}

3.代码演示

image-20211110115602351

子进程已经执行完 < defunct >,父进程还在执行,所以父进程没有办法释放子进程的空间,那么子进程就变成了僵尸进程

6.2.3 进程回收-wait 函数使用

image-20211110120907998

进程退出时内核回收资源,主要是 PCB 中的信息

1.API

image-20211110121358927

返回值设置:

子进程状态改变:返回状态改变的子进程 pid

子进程状态没有改变 return 0

失败:返回 -1

此函数的阻塞行为:

调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时才被唤醒(相当于继续往下执行)

如果没有子进程了,函数立刻返回,返回-1;如果子进程都已经结束了,也会立即返回,返回-1.

2.代码

1.不获得子进程被杀死时的状态

首先先创建 5 个子进程

父进程进入无限循环状态:首先打印一个 id ,然后使用 wait 函数将父进程阻塞

子进程也要执行一段无限循环的代码,但是在父进程在阻塞的情况下可以用 kill -9 将子进程杀死

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    //创建 5 个子进程
    pid_t pid;
    for(int i=0;i<5;i++){
        pid=fork();// 为了避免孙子进程,使用相同的pid 创建子进程
        if(pid==0) break; // 子进程不进行任何操作
    }
    if(pid>0){
        // 父进程一直执行
        while(1){
            printf("parent:%d\n",getpid());
            // 父进程在打印一句话之后进入阻塞状态
            int ret = wait(NULL); // 传入 NULL 则不处理任何状态
            if(ret==-1){ // 父进程阻塞失败或者没有子进程可以杀了,返回 -1
                printf("all child die,pid=%d\n",ret);
                break;
            }
            // 所有的子进程全部处理完毕,打印
        }
    }
    else if(pid==0){
        while(1){
            // 子进程操作
            printf("child:%d\n",getpid());
            sleep(1);
        }
    }
    return 0;
}
image-20211110130444851

2.获得子进程被杀死时的状态

image-20211110132040456

父进程相关判断代码:

int st; // 定义一个赋值参数,函数可以向这个参数赋值
int ret = wait(&st); // 让父进程等进程结束

if(ret == -1) { 
    break;
}
// 判断子进程杀死的状态
if(WIFEXITED(st)) {
    // 是不是正常退出
    printf("退出的状态码:%d\n", WEXITSTATUS(st));
}
if(WIFSIGNALED(st)) {
    // 是不是异常终止
    printf("被哪个信号干掉了:%d\n", WTERMSIG(st));
}

子进程相关退出代码:

exit(0); // 在子进程相应的代码块中调用 exit ,在 exit 中传入相应参数则父进程的 wait 函数就会接收到
kill -9 pid // 下方显示的效果

image-20211110134016646

4.知识扩展–如何创建子进程

pid_t pid;
for(int i=0;i<5;i++){
    pid=fork();// 为了避免孙子进程,使用相同的pid 创建子进程
    if(pid==0) break; // 子进程不进行任何操作
}

如何防止创建孙子进程。因为子进程也是需要执行程序文件的。如果不断的使用 fork()去调用子进程执行到这个方法还会在创建子进程的子进程,所以要想创建多个子进程就要用同一个 fork 方法

虽然使用的都是相同的 pid ,但是子进程的 id 却不同

image-20211110124015900

6.2.4 进程回收-waitpid 方法使用

wait() 方法在进程回收时只能阻塞父进程,waitpid 方法回收进程时有更多的选项

**1.API **

image-20211111103215881

2.代码

int st;
int ret = waitpid(0,&st,0);// 监控进程变化

完整代码

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    pid_t pid;
    // 创建 5 个子进程
    for(int i=0;i<5;i++){
        pid = fork();
    }
    // 判断当前进程
    if(pid>0){
        while(1){
            printf("i am parent:%d",getpid());
            // 监控进程
            int st;
            int ret = waitpid(0,&st,0);// 监控进程变化
            if(ret==-1){
                break;
            }
            else if(ret==0){ //说明还有子进程没有改变状态
                continue;
            }
            else if(ret>0){ // 如果子进程状态发生了变化
                if(WIFEXITED(st)){
                    // 是不是正常退出
                    printf("退出的状态码:%d\n", WEXITSTATUS(st));
                }
                if(WIFSIGNALED(st)) {
                    // 是不是异常终止
                    printf("被哪个信号干掉了:%d\n", WTERMSIG(st));
                }
                printf("child die, pid = %d\n", ret);
            }
        }
    }
    else{
        while(1){
            printf("child pid%d\n",getpid());
            sleep(1);
        }
        exit(0);
    }
    return 0;
}

3.代码演示

代码演示像上面一样

面试:7.进程通信 IPC

7.1 相关概念

1.什么是 IPC

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC 的⽅式通常有管道

(包括⽆名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams 等。其中 Socket 和 Streams ⽀

持不同主机上的两个进程 IPC。

Linux 中如何进行进程通信

image-20211111114433675

7.2 管道

7.2.1 管道定义

image-20211111115635646

匿名管道就是我们俗称的管道。ls 可以理解为一个文件,这个文件实现的是将当前目录下的所有文件名显示到终端。但是管道有一个重定向作用,它不将文件名显示在终端而是显示在另一个进程文件 wc 中

管道就是在内存中的缓冲器

7.2.2 管道的特点

image-20211111121048870

1.管道是一个保存在内存中的缓冲区,保存在内核空间

2.管道和有名管道的区别

3.管道是一个字节流

4.管道读写的数据是顺序的,数据结构是队列

5.管道是半双工,具有固定的读端和写端

单工:遥控器只能向电视发送信号,但是电视不能向遥控器发送信号

半双工:类似对讲机,虽然两个人可以相互发消息,但是有一方发消息的时候另一方就要等着

双攻:二者同时相互的发送消息

6.管道数据被读走就永远被抛弃,管道的数据结构是循环队列

当在队列中前面的数据产生删除后,队列还是可以被利用

image-20211111122306527

7.匿名管道只能在有关系的进程间通信

比如说父子进程,他们使用的是同一个文件描述符表,所以父进程的文件描述符 fd 对应的管道也和子进程文件描述符对应的管道是一样的

但是如果是无关的进程,虚拟空间不存在同一指向问题,所以相同的文件描述符 fd 对应的可能是不同的管道

7.3管道的相关函数

7.3.1 pipe–创建匿名管道

1.API

image-20211111130834690

一定要在 fork 之前创建管道,否则进程已经创建完了管道不一定对应的是同一个管道。

pipe 返回的是文件描述符,一个对应管道读端,一个对应管道写端

管道默认是阻塞状态,也就是说子进程如果向父进程发送数据,但是管道中没有数据, read 阻塞,如果管道满了 write 阻塞

2.代码

实现子进程向父进程发送数据

int ret = pipe(pipefd); // 创建管道,得到管道输入端和输出端的文件描述符
write(pipefd[1],str,strlen(str)); // 先向管道中写入数据
read(pipefd[0],buf,sizeof(buf)); // 从管道中读取数据
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
int main(){
    // 定义传出参数
    int pipefd[2];
    // 在创建子进程之前创建管道
    int ret = pipe(pipefd);
    if(ret==-1) perror("pipe");
    // 创建子进程
    pid_t  pid;
    pid = fork(); 
    if(pid>0){ // 父进程读取数据
        char buf[1024]={0};
        int len = read(pipefd[0],buf,sizeof(buf)); // 传入读取端的描述符
        printf("parent recv:%s,pid:%d\n",buf,getpid());
    }
    if(pid==0){// 子进程写入数据到管道
        char* str = "hello world";
        write(pipefd[1],str,strlen(str)); // 传入写入端的描述符
    }
    return 0;
}

PS: 视频末尾还有一个 while 循环的事实消息发送我没有实现

3.代码演示

从下面就可以看到父进程收到了子进程发来的消息

image-20211111132828255

4.管道之间的相互通信

7.3.2 alimit Linux 指令查看管道大小

ulimit -a
image-20211111135201280

每个管道中有 8 块,每一块是 512 的大小,4K

更改管道大小

ulimit -p

7.3.3 fpathconf–查看管道大小

关键代码

long size = fpathconf(pipefd[0], _PC_PIPE_BUF);
printf("pipe size : %ld\n", size);
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {

    int pipefd[2];

    int ret = pipe(pipefd);

    // 获取管道的大小
    long size = fpathconf(pipefd[0], _PC_PIPE_BUF);

    printf("pipe size : %ld\n", size);

    return 0;
}

执行文件输出管道大小

image-20211111135454268

7.3.4 C 实现 Linux 管道通讯指令

代码在 lesson22 parent_child.c

image-20211112105848647

其实在 Linux 中指令 ps aux | grep xxx 操作就是实现 ps 进程和 grep 进程之间的通讯

1.代码

Step1:

创建一个管道:用于两个进程通信

Step2:

创建子进程,对父进程和子进程判断

Step3:

子进程:

​ 先将 ps 原先要输出的地方进行重定向,将控制台的输入输出输入到管道

​ 执行 ps 指令

父进程:

​ 读取管道中的数据

int main(){
    // 0.首先创建管道
    int fd[2];
    pipe(fd);
    // 1.创建子进程
    pid_t pid = fork();
    // 2.判断进程
    if(pid>0){ // 进行读操作
        // 关闭写端
        close(fd[1]);

        // 从管道中循环的取数据
        int len =-1;
        char buf[1024]={0};
        while((len=read(fd[0],buf,sizeof(buf)-1))>0){
            // 数据的处理操作
            printf("%s",buf);
            memset(buf,0,1024); // 清空 buf 中的值
        }
        wait(NULL); // 阻塞自己等待子进程执行完毕
    }
    else if(pid==0){ // 写操作
        // 关闭读端
        close(fd[0]);
        // 文件描述符重定向:将数据在控制台打印
        dup2(fd[1],STDOUT_FILENO);
        // 执行 ps aux
        execlp("ps","ps","aux",NULL);
        exit(0);
    }
    return 0;
}

2.代码演示

可以看到读取到了相关的进程数据

image-20211112114626313

3.需要注意

某一个进程不可以同时进行读操作或者写操作,所以当一个进程进行读操作时就要将写操作进行关闭

close(fd[1]); // 关闭写操作

7.4 管道的读写特点

读管道:

​ 管道中有数据:read 返回实际读到的字节数。==》 这是正常情况

​ 管道中无数据:

​ 写端被完全关闭,read 返回 0 ,相当于读到文件末尾

​ 写端没有完全关闭:read 以为写端还要写入数据,read 阻塞等待

写管道:

​ 读端全部关闭:写管道本想写,但是没有读端,进程异常终止 (进程收到 SIGPIPE信号)

​ 管道读端没有全部关闭:

​ **管道以满:**这时候不能再向管道中写入数据,write 阻塞

​ **管道没有满:**write 将数据写入,并返回实际写入的字节数 ==》 这是正常情况

7.4.1 设置管道非阻塞

管道就是文件描述符,如果想要设置管道非阻塞就要设置文件描述符为 open 状态

更改文件状态 fcntl

1.API

image-20211112121659547

2.读操作阻塞时的代码

在子进程中每发送完一段数据 write 端就进行阻塞,即 sleep 操作,写操作是没有被完全关闭的,这时候读操作阻塞

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
/*
    设置管道非阻塞
    int flags = fcntl(fd[0], F_GETFL);  // 获取原来的flag
    flags |= O_NONBLOCK;            // 修改flag的值
    fcntl(fd[0], F_SETFL, flags);   // 设置新的flag
*/
int main() {

    // 在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1) {
        perror("pipe");
        exit(0);
    }

    // 创建子进程
    pid_t pid = fork();
    if(pid > 0) {
        // 父进程
        printf("i am parent process, pid : %d\n", getpid());

        // 关闭写端
        close(pipefd[1]);

        // 从管道的读取端读取数据
        char buf[1024] = {0};
        while(1) {
            int len = read(pipefd[0], buf, sizeof(buf));
            printf("len : %d\n", len);
            printf("parent recv : %s, pid : %d\n", buf, getpid());
            memset(buf, 0, 1024);
        }

    } else if(pid == 0){
        // 子进程
        printf("i am child process, pid : %d\n", getpid());
        // 关闭读端
        close(pipefd[0]);
        char buf[1024] = {0};
        while(1) {
            // 向管道中写入数据
            char * str = "hello,i am child";
            write(pipefd[1], str, strlen(str));
            sleep(5);
        }

    }
    return 0;
}

3.代码演示

image-20211112122936052

5.更改文件描述符属性,让 read 不阻塞

关键代码:

需要在父进程中添加对读指令的 open 操作,使用 fcntl 指令

int flags = fcntl(pipefd[0], F_GETFL);  // 获取原来的flag
flags |= O_NONBLOCK;            // 修改flag的值
fcntl(pipefd[0], F_SETFL, flags);   // 设置新的flag

父进程的进程操作如下:

int flags = fcntl(pipefd[0], F_GETFL);  // 获取原来的flag
flags |= O_NONBLOCK;            // 修改flag的值
fcntl(pipefd[0], F_SETFL, flags);   // 设置新的flag
while(1) {
    int len = read(pipefd[0], buf, sizeof(buf));
    printf("len : %d\n", len);
    printf("parent recv : %s, pid : %d\n", buf, getpid());
    memset(buf, 0, 1024);
    sleep(1);
}

6.设置不阻塞后代码演示

和上面代码相比这里 read 不阻塞后会一直打印数据,只不过这时候管道中没有数据,所以打印的数据就是 -1

image-20211112124138013

7.3 有名管道

(1)FIFO 可以在⽆关的进程之间交换数据,与⽆名管道不同;

(2)FIFO 有路径名与之相关联,它以⼀种特殊设备⽂件形式存在于⽂件系统中。

有名管道可以进行非“关系” 间的节点通信,就定义了一个文件,两个进程通讯时就是对那个文件进行读写操作

数据结构:关系队列

与普通文件的区别是,有名管道生成的文件在读出之后就不存在了

7.3.1 使用 Linux 命令行创建有名管道 fifo

1.指令

mkfifo fifo // 定义一个名字叫 fifo 的有名管道

2.命令演示

创建完 fifo 之后,在所在目录下生成了一个 fifo 的文件

image-20211112134756724

这里向 fifo 这个文件写入数据 hello world 。写入完数据后进程阻塞,是因为这个 fifo 在等待读取

image-20211112134651875

7.3.2 mkfifo 函数创建有名管道

代码在lesson23

1.API

image-20211112134935892

这里赋予的文件权限类似于文件的文件权限

2.代码:实现两个进程间的通信

①write 文件,创建有名管道,并向管道中写数据

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<string.h>
int main(){
	// 创建管道之前先判断管道是否存在
	int ret = access("test",F_OK); // 判断一个文件是否存在
	if(ret==-1){ // 管道不存在返回 -1 
		printf("管道不存在正在创建中");
		mkfifo("test",0664);
	}
	// open 管道文件的文件描述符
	int fd = open("test",O_WRONLY);
	for(int i =0 ;i<100;i++){
		char buf[1024];
		sprintf(buf,"hello,%d\n",i);
		printf("write data:%s\n",buf);
		write(fd,buf,strlen(buf));
		sleep(1);
	}
	close(fd);
	return 0;
}

②read,创建读操作,将数据读出

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main(){
	// 打开管道
	int fd = open("test",O_RDONLY);
	char buf[1024] = {0};
	while(1){
		int len = read(fd,buf,sizeof(buf));
		if(len==0){
			printf("写端断开连接");
			break;
		}
		printf("recv buf:%s\n",buf);
		memset(buf,0,1024);
	}
	close(fd);
	return 0;
}

3.代码演示

首先先执行 write.c 的文件,但是因为 read 还没有打开,所以这时候的write是阻塞状态

image-20211112152223190

然后执行 read 文件,read 文件就接着可以显示读到的数据

image-20211112152710312

与此同时 write 控制台也开始写文件

image-20211112152836247

当关掉其中一个时另一个也就不读或者不写了,这是因为发生了读、写操作的阻塞

image-20211112152912272

7.4 聊天功能实现–有名管道实战

代码详见 lesson24

7.4.1 整体流程

这里需要创建两个管道,因为一个进程只能控制管道的一端,如果要实现双向通信需要两个管道。

image-20211113095304185

7.4.2 代码

导入相关库文件

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

1.A 端代码

①创建有名管道

创建有名管道时判断有名管道文件是否存在

// 创建有名管道1
    int ret = access("fifo1",F_OK);
    if(ret==-1){
        printf("管道 1 创建中。。。\n");
        ret = mkfifo("fifo1",0664); // A 对于管道1 使用只写的方式打开
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }else{
            printf("打开管道1成功。。。\n");
        }
    }
    // 创建有名管道2
    ret = access("fifo2",F_OK);
    if(ret==-1){
        printf("管道 2 创建中。。。\n");
        ret = mkfifo("fifo2",0664); // A 对于管道1 使用只写的方式打开
        if(ret==-1){
            perror("mkfifo");
            exit(0);
        }else{
            printf("打开管道2成功。。。\n");
        }
    }

②分别获得两个管道的写入端和读取端

// 对于两个管道的操作
int fd1 = open("fifo1",O_WRONLY);
int fd2 = open("fifo2",O_RDONLY);

③ while 循环监听两端读取操作

char buf[128];
while(1){ // A 的监听操作
    memset(buf,0,128);
    fgets(buf,sizeof(buf),stdin); // 最后一个参数是从哪里获得这里是从控制台的标准输入输出获得
    write(fd1,buf,sizeof(buf));
    memset(buf,0,128);
    // 定义读操作
    ret = read(fd2,buf,sizeof(buf));
    printf("A recv:%s\n",buf);
}

④关闭两端

// 关闭两个管道
close(fd1);
close(fd2);

2.B 端关键代码

①获得两个管道的通配符

// 对于两个管道的操作
int fd1 = open("fifo1",O_RDONLY);
int fd2 = open("fifo2",O_WRONLY);

② while 循环监听输入输出操作

char buf[128];
while(1){ // B 的监听操作
    memset(buf,0,128);
    // 定义读操作
    ret = read(fd1,buf,sizeof(buf));
    printf("B recv:%s\n",buf);
    memset(buf,0,128);
    fgets(buf,sizeof(buf),stdin); // 最后一个参数是从哪里获得这里是从控制台的标准输入输出获得
    write(fd2,buf,sizeof(buf));
}

7.4.3 代码演示

下图所示,AB 两端的文件都可以收到

现在的 Bug 就是读写都在一个进程中:

有可能发生阻塞的情况。

比如 A 代码中先定义写操作,这个时候 B 向 A 发送消息 A 是读不到的

但是 B 先定义的是读操作,如果 A 先给 B 发送消息 ,B 可以正常读到

image-20211113111215469
COMSOL实现裂缝性储层油水两相流模拟的关键技术 多孔介质中的流体流动模拟是油气藏开发的核心技术,其基本原理基于达西定律和质量守恒方程。在裂缝性储层中,离散裂缝网络与基质系统的耦合流动带来了特殊的数值挑战。通过COMSOL Multiphysics平台实现的多物理场耦合技术,可以精确模拟油水两相在复杂裂缝系统中的渗流行为。该技术采用Level Set方法表征裂缝几何形态,结合自适应网格生成技术解决狭窄裂缝的网格剖分难题,并创新性地引入Bang-Larsen毛管压力滞后模型,显著提高了采收率预测精度。这些方法在致密油藏开发、水驱优化等工程实践中具有重要应用价 阅读详情

相关推荐

学习笔记|多样本单因素方差分析|事后比较|方差齐性|F检验|韦尔奇检验|两独立样本T检验|两样本方差分析|规范表达|《小白爱上SPSS》课程:SPSS第七讲 | 单因素方差分析怎么做?

学习笔记|多样本单因素方差分析|事后比较|方差齐性|F检验|韦尔奇检验|两独立样本T检验|两样本方差分析|规范表达|《小白爱上SPSS》课程:SPSS第七讲 | 单因素方差分析怎么做?

Medlar_CN的博客 9515

4.5、进程相关

进程:程序执行时,所需要的资源的集合总称 程序的一次执行过程 程序:一些指令的集合,存在在磁盘空间中,是静态的 进程:动态的执行过程(创建、调度、执行、消亡),指令的执行过程 程序包含: 1、用户数据段 2、正文段 进程包含的内容: 1、用户数据段:存放的是全局变量、常数以及动态数据分配的数据空间 2、正文段:存放的是程序中的代码 3、系统数据段 系统数据段包含: 1、进程控制块 2、cpu中pc寄存器 3、堆栈 进程控制块PCB 1、进程号 pid(在系统中进程的唯一识别) 2、进程优先级、状态 3、进程

feiffer·hu的博客 383

VScode搭建Opencv(C++开发环境)

VScode配置Opencv一、准备软件二 、下载软件1、MinGw下载2、 Cmake下载3、Opencv下载三、编译1、cmake-gui2、make3、install四、 VScode配置1、launch.json2、c_cpp_properties.json3、tasks.json五、测试 用了半天事件,看了各种的博客终于配置成功了,在这里记录并分享一下,让更多的人少走弯路。 本次环境是Win 10. 一、准备软件 我们本次用到的3个软件,(建议读者文件路径,文件版本 尽量都和我相同,这样不容易出错

河旬的博客 8万+

4.进程相关 2

使用kill -l就可以看到所有的信号前 31 个为常规信号,其余为实时信号只看红色部分-9 SIGKILLSIGCHLD:子进程结束时,父进程会收到这个信号下图中的 Core 文件是指我们在终止进程时对于中止进程保存的相关信息man 7 signal // 查看信号指令可以发现有的信号用三个数字表示,这是因为不同的系统架构造成的,我们在使用这些信号时选择中间的数字即可SIGKILL and SIGSTOP 不能被捕捉,不能被阻塞,也不能被忽略。

许挂挂的博客 597

MTK手机传感器驱动开发避坑指南:从SCP代码大小限制到Overlay加载流程详解

本文详细解析了MTK平台传感器驱动开发中的常见问题,包括SCP代码大小限制、Overlay加载流程及客制化传感器集成。通过实战案例和优化策略,帮助开发者高效解决MTK传感器驱动开发中的技术难题,提升开发效率。

weixin_42522374的博客 401

量子密钥分发系统的工程实践(四):FPGA在后处理中的核心实现与优化

本文深入探讨了FPGA在量子密钥分发(QKD)系统后处理中的核心实现与优化策略。文章详细拆解了FPGA如何高效完成原始密钥提取、误码协商和私密放大等关键任务,并分享了流水线设计、资源复用及存储器架构优化等工程实践“心法”,旨在解决高速、实时QKD系统中的性能瓶颈,提升密钥生成率。

t8u9v0的博客 388

4.进程相关2

8.内存映射 8.1 内存映射相关定义 创建一个文件,将保存在磁盘中的文件映射到内存中,后期两个进程之间对内存中的数据进行操作,大大减少了访问磁盘的时间,也是一种最快的 IPC ,因为进程之间可以直接对内存进行存取 8.2 内存映射相关的系统调用 代码地址:lesson25 8.2.1 mmap & munmap 函数–内存的映射与释放 1.API mmap : 将一个文件映射到内存中 这个函数返回的是内存映射出来的内存首地址 munmap : 解除一个文件和内存的映射 内存映射和管道不一样,

许挂挂的博客 436

GD32H7实战:5步搞定YOLO轻量化模型部署到MCU(附避坑指南)

本文详细介绍了如何将YOLO轻量化模型部署到GD32H7 MCU的完整实战流程。通过五个关键步骤,涵盖环境搭建、模型训练、格式转换到工程集成,并重点分享了使用GD32AI-ModelZoo工具链进行MCU部署的避坑指南,帮助开发者在资源受限的边缘设备上实现高效目标检测。

weixin_29070861的博客 445

chrome为什么是4个进程和Tcp相关

chrome浏览器原理过程01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程? 01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程? 从图中可以看出,最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。 下面我们来逐个分析下这几个进程的功能。 浏览器进程。主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。 渲染进程。核心任务是将 HTML、CSS 和 JavaScr

blue_go_go的博客 497

RT-DETR改进策略【卷积层】| CGblock 内容引导网络 利用不同层次信息,提高多类别分类能力 (含二次创新)

本文记录的是利用中的模块优化的目标检测网络模型。通过局部特征提取器、周围环境提取器、联合特征提取器和全局环境提取器来提取局部特征、周围环境和全局环境信息,充分利用不同层次的信息。本文将其应用到中,并进行二次创新,使网络能够更好的处理多类别目标的分类能力。CGNet: A Light-Weight Context Guided Network for Semantic Segmentation1️⃣ 首先通过局部特征提取器floc(∗)floc(*)floc(∗)和周围环境提取器fsur(∗)f_{sur }

Limiiiing的博客 1350

Python爬虫实战:逆向解析天猫商品详情API,精准捕获规格、SKU与促销活动

及浏览器开发者工具),绕过前端渲染的复杂性,直接逆向分析并调用其内部数据接口,从而高效、稳定地抓取商品的关键信息,包括商品规格、多维度SKU信息以及复杂的促销活动。print(f"SKU ID: {sku.sku_id}, 价格: ¥{sku.price}, 库存: {sku.stock}, 规格: {sku.props}")当你访问一个商品链接时,浏览器首先会加载一个几乎为空的HTML骨架,然后通过执行大量的JavaScript代码,向后台服务器发起多个异步请求,最终将获取到的数据填充到页面中。

2201_76125261的博客 1129

day4 操作目录相关的函数,进程,进程相关的函数

操作目录相关的函数,进程,进程相关的函数

m0_74205826的博客 96

关于 ABAP OPEN SQL 的动态 WHERE 条件和 Dynamic Selections

ABAP动态查询技术解析 本文介绍了ABAP中实现灵活数据库查询的动态选择技术,通过FREE_SELECTIONS函数组实现用户自定义查询条件。核心内容包括: 传统固定WHERE条件的局限性,无法满足业务多变需求 Dynamic Selections机制的工作原理,使用FREE_SELECTIONS_INIT初始化、FREE_SELECTIONS_DIALOG交互 完整Demo程序演示如何构建通用表数据浏览器: 用户输入表名后校验权限 调用动态选择函数生成条件 动态拼接WHERE子句执行查询 使用CL_SA

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 674

[ DOS 命令基础 4 ] DOS 命令命令详解-端口进程相关命令

我们搞网络安全需要经常用到 dos 命令,比用拿到 windows 的 shell,需要使用 dos 命令。再比如 bat 脚本,我们经常需要使用。这里我将开始详细介绍一些常用的 dos 命令。本文先讲解与端口进程相关的命令。

qq_51577576的博客 1140

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【Linux-4】进程概念(相关进程与环境变量)

目录: 进程的调度算法 task_struct结构体 模拟实现僵尸进程,孤儿进程 《深入理解计算机系统》虚拟内存 《操作系统精髓设计原理》进程 使用setenv,export等环境变量 1.进程的调度算法 1> 时间片轮转调度算法(RR) 2>先来先服务调度算法(FCFS) 3>优先级调度算法(HPF) 4>多级反馈队列调度算法 5>高响应比优先...

weixin_44768184的博客 334

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ORACLE RAC中的oc4j和gsd资源以及RAC相关的进程

1.RAC相比单实例数据库多出的进程: LMS - Gobal Cache Service Process 全局缓存服务进程 LMD - Global Enqueue Service Daemon 全局查询服务守护进程 LMON - Global Enqueue Service Monitor全局查询服务监视进程 LCK0 - Instance Enqueue Process 实例查询进程 D...

weixin_33908217的博客 415

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

4.【Windows API程序设计】线程与进程的相关API函数

本文介绍了Windows系统中进程和线程的基本操作。主要内容包括:1) 使用CreateProcess函数创建进程,详细说明其参数和STARTUPINFO、PROCESS_INFORMATION结构体;2) 遍历进程的方法,通过CreateToolhelp32Snapshot、Process32First和Process32Next函数获取系统进程信息;3) 终止进程的ExitProcess和TerminateProcess函数;4) 使用CreateThread创建线程,说明其参数和注意事项。

2503_92964515的博客 617

DAY4 IO进程线程,库(静态库、动态库)的创建及使用,以及进程的相关指令的使用

IO进程线程,库(静态库、动态库)的创建及使用,以及进程的相关指令的使用

weixin_46260677的博客 509

4.5 进程调度_与调度相关的系统调用

<br />    Linux提供了一族系统调用,用于管理与调度程序相关的参数。这些系统调用可以用来操作和处理进程优先级、调度策略及处理器,同时还提供了显示的将处理器交给其他进程的机制。<br /> 4.5.1 与调度策略和优先级相关的系统调用<br /> 4.5.2 与处理器绑定有关的系统调用<br /> 4.5.3 放弃处理器时间<br />    Linux通过sched_yield()系统调用,提供了一种让进程显式地将处理器时间让给其他等待执行进程的机制。它是通过将进程从活动队列中移到过期队列中实现

cxf100900的专栏 616

Oracle gsd服务是什么,OracleRAC中的oc4j和gsd资源以及RAC相关的进程

ORACLE RAC中的oc4j和gsd资源以及RAC相关的进程1.RAC相比单实例数据库多出的进程:LMS - Gobal Cache Service Process 全局缓存服务进程LMD - Global Enqueue Service Daemon 全局查询服务守护进程LMON - Global Enqueue Service Monitor全局查询服务监视进程LCK0 - Instanc...

weixin_35916239的博客 683

Linux进程 --- 4(环境变量相关)

根据前面文章的学习, 我们已经对于Linux进程有了个大概的了解,但是其中的内容并不只是那么一点,接下来的内容也将会收获满满。

qiuyunoqy的博客 777

UE4笔记-进程/线程/网络/IO模块的相关问题记录

吐槽:如果有Qt的开发经验,会发现其实在比较底层编程理念UE4和Qt极其相识.很多类名和用法甚至都是相同的. Q.创建线程类:   UE4文档没有特别介绍关于线程模块的文章,这里自己简单记录一下,备查. 目前来说UE4的线程模块还是比较简陋的,命名风格像C#和Qt的结合体-_,- UE4的线程的有两种比较常用的方式: 1.异步编程便捷帮助函数 2.自定义线程类   有复杂...

weixin_30894583的博客 311

嵌入式Linux学习笔记(4)-进程处理相关系统调用

进程是计算机中正在运行的程序的实例。它是操作系统分配资源和调度任务的基本单位。每个进程都有自己的地址空间、内存、文件描述符、线程等资源。进程可以包括一个或多个线程,这些线程共享同一进程的资源,并在同一进程中执行并发任务。进程之间是相互独立的,彼此之间不能直接访问对方的资源,但可以通过进程间通信来进行数据交换。操作系统通过分配时间片给各个进程,使得它们在单个处理器或多个处理器上能够并发地运行。进程的创建、结束和切换是由操作系统负责管理的。

汘荨的博客 1431

Linux简介(4)--计算机组成与进程及相关命令

文章目录计算机的基本组成计算机组成五大部件系统总线指令进程PIDPCB进程信息进程描述信息:进程控制信息资源信息现场保护信息(cpu进行进程切换时)进程状态进程管理命令pspstreejobssleep&fg bgkillpkillkillalltoppidstat -u故障诊断思路 计算机的基本组成 计算机组成五大部件 (1)运算器:也叫算数逻辑单元,完成对数据的各种常规运算,如加减乘除,也包括逻辑运算,移位,比较等。 (2)控制器:它是整个计算机系统的控制中心,它指挥计算机各部分协调地工作,

降温的博客 290

操作系统笔记:2.1.1——2.1.4进程相关知识

操作系统进程的知识

tjh1998的博客 487
上一篇: 3.C++ Make
下一篇: 4.进程相关 2
许菠萝
博客等级 码龄10年 263粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值