Linux进程概念

1. 了解冯.诺依曼体系结构
2. 了解操作系统,并且知道操作系统如何进行管理?
3. 进程相关概念,进程和程序的区别,父进程和子进程
3. 进程的状态及其如何修改进程的状态

冯.诺依曼体系结构


我们常见的计算机:笔记本,台式计算机。而不常见的如服务器,大部分都遵循冯诺依曼体系

这里写图片描述

组成:
 7. 输入单元:包括键盘,鼠标,扫描仪,写板等
 8. 输出单元:显示器,打印机等
   另外,输入设备和输出设备都属于外设,基本上所有的外设都和IO有关
 9. 中央处理器(CPU):含有运算器和控制器等
 10. 存储器:这里指的是内存
所有的设备都只能直接和内存打交道:
1. 外设(输入设备或者输出设备) 只能直接和 存储器(内存) 打交道

1. CPU 只能直接和 存储器(内存)打交道

更好的了解一下冯诺依曼体系结构:
两个人通过计算机聊天的例子:

发送者:
    通过输入设备(键盘)发送消息,然后通过(内存)对数据进行封装,发送到输出设备(网卡)
接受者:
    通过输入设备(网卡)接受消息,然后通过(内存)对数据进行解包,发送到输出设备(显示)

如果是发送文件的话,接受者对应的输入设备是硬盘,这样关掉计算机,也会收到消息,内容还在。

操作系统(Operator System)


操作系统:任何计算机系统都包含一个基本的程序集合。
其作用就是:在整个计算机软硬件架构中,它是用来搞“管理”的软件
操作系统包括:

1. 内核:
   内存管理  进程管理  文件管理  驱动管理
2. 其他程序
   比如:函数库 shell程序
设计操作系统的目的:
1. 与硬件交互,管理所有的软硬件资源 (对系统软硬件部分)
2. 为用户程序(应用程序) 提供一个良好的执行环境 (对用户)
如何进行管理?
1. 管理是通过数据进行管理的
2. 管理者和被管理者不进行直接沟通

进程


基本概念:
进程:(每个进程都有自己的状态和独立的地址空间。)

进程由操作系统管理

从用户角度看:  进程是程序的一次动态执行过程。
    分时系统: 时间片轮转。
  从操作系统: 进程是操作系统分配资源的基本单位(最小单位)
描述进程—PCB(进程控制块)
  1. 如何描述一个进程?
1.描述一个进程需要知道进程信息,而进程信息放在一个叫做进程控制块的数据
构中,这个进程控制块就是PCB。
2.PCB也可以理解为一个进程属性的集合。
  1. Linux操作系统下具体的PCB是:task_struct
task_struct
1. task_struct: 是Linux中描述进程的结构体
2. tsk_struct: 是Linux内核中的一个数据结构,它被装载在RAM(内存)中且包含了进程的信息
如何管理一个进程?
1. 将进程描述起来    
而具体描述的方法是结构体task_struct(我们把描述进程的结构体叫做PCB)       
2. 将结构体组织起来
用链表  (所有运行在系统里的进程都以task_struct链表的形式存在内核里。)

所以如果管理一个进程,只需要管理好它的PCB

查看进程
第一种方法:通过 ls /proc 文件夹查看
前面的第一列便是进程id
[root@localhost day01_6.12]# ls /proc
1     15    1653  1833  2098  2210  2339  2385  2405  2611  2667  30    365  716        cmdline      interrupts  kpageflags  net           sys
10    151   1678  1846  21    2216  2344  2386  2407  2612  2669  3070  37   8          cpuinfo      iomem       loadavg     pagetypeinfo  sysrq-trigger
11    152   1687  1883  2100  2258  2347  2387  2420  2615  2670  31    38   892        crypto       ioports     locks       partitions    sysvipc
12    1521  1688  19    2102  2269  2352  2388  2422  2617  2685  3126  4    893        devices      ipmi        mdstat      sched_debug   timer_list
1250  153   17    2     2108  2275  2357  2389  2470  2619  2693  3130  40   9          diskstats    irq         meminfo     schedstat     timer_stats
1271  1546  1720  20    2109  2290  2362  2392  25    2627  27    3131  41   941        dma          kallsyms    misc        scsi          tty
1299  16    1730  2018  2110  23    2370  2393  26    2631  271   3150  5    acpi       driver       kcore       modules     self          uptime
13    1617  1735  2066  2121  2301  2371  2399  2601  2632  274   3172  6    asound     execdomains  keys        mounts      slabinfo      version
14    1628  1755  2077  2124  2309  2373  24    2604  2633  28    32    662  buddyinfo  fb           key-users   mpt         softirqs      vmallocinfo
144   1634  1771  2091  2140  2310  2382  2401  2607  2659  29    3201  7    bus        filesystems  kmsg        mtd         stat          vmstat
145   1647  18    2096  22    2330  2383  2402  2609  2661  3     3218  71   cgroups    fs           kpagecount  mtrr        swaps         zoneinfo

第二种方法:更详细的查看进程信息

[root@localhost day01_6.12]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   2900  1440 ?        Ss   Jun11   0:01 /sbin/init
root         2  0.0  0.0      0     0 ?        S    Jun11   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    Jun11   0:00 [migration/0]
root         4  0.0  0.0      0     0 ?        S    Jun11   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S    Jun11   0:00 [migration/0]
root         6  0.1  0.0      0     0 ?        S    Jun11   0:26 [watchdog/0]
root         7  0.0  0.0      0     0 ?        S    Jun11   0:01 [events/0]

进程和程序的区别


程序:完成特定任务的一系列指令集合。

这里写图片描述

这里写图片描述

进程和程序的区别:

程序: 数据+代码

进程: 数据+代码+堆栈+PCB

PCB: 进程控制块 (Process.Control.Block)

(每个进程有一个PCB表示)———用链表存储

并发:多个进程在一个cpu下采用进程切换的方式,在一段时间之内让多个进程得以推进。
并行:多个进程在多个CPU下分别.同时进行。
1. 进程是动态的,程序是静态的;
2. 进程的生命周期是短暂的,而程序相对永久;
3. 进程有重要的数据结构PCB;
4. 一个进程只能对应一个程序
   而一个程序可以对应多个进程。

父进程和子进程


通过系统调用获取进程标识符:
子进程id: PID   通过getpid()函数获取
父进程id: PPID  通过getppid()函数获取

这两个函数都在 <sys/types.h> <unistd.h>

获取父子进程id:

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7     printf("pid:%d ppid:%d \n%",getpid(),getppid());                                                                                                          
  8     return 0;
  9 }

结果:

[root@localhost day01_6.12]# gcc test.c
[root@localhost day01_6.12]# ./a.out
pid:3311 ppid:3201 
[root@localhost day01_6.12]# 
[root@localhost day01_6.12]# ./a.out
pid:3312 ppid:3201 
[root@localhost day01_6.12]# ./a.out
pid:3313 ppid:3201 
[root@localhost day01_6.12]# ./a.out
pid:3314 ppid:3201 
[root@localhost day01_6.12]# ./a.out
pid:3315 ppid:3201 
[root@localhost day01_6.12]# ./a.out
pid:3316 ppid:3201 

结果发现,每一次运行之后,父进程是不会变的,子进程会变。
而如果让代码死循环起来,这个就是一个进程,始终不能退出,所以效果就是:

1   #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7     while(1){
  8     printf("pid:%d ppid:%d \n%",getpid(),getppid());
  9     sleep(1);
 10     }
 11 
 12     return 0;                                                                                                                                                 
 13 }
[root@localhost day01_6.12]# gcc test.c
[root@localhost day01_6.12]# ./a.out
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
pid:3351 ppid:3201 
^C
[root@localhost day01_6.12]# 
通过系统调用创建进程—fork()
1. 运行 man fork 认识fork

[root@localhost day01_6.12]# man fork


2. 发现fork() 有两个返回值

3. 父子进程代码共享,数据各自开辟空间,私有一份采用(写时拷贝)

一个简单的代码来了解fork():

 1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7     fork();
  8     printf(" hello world!,pid: %d,ppid: %d\n ",getpid(),getppid());                                                                                           
  9     sleep(1);
 10     return 0;
 11 }

看似只有一个printf,只会输出一个hello world.而其实调用了fork()函数,它的作用是创建进程,类似于一个叉子的结构,一分为二(简单认为叉子的另外一头只有两个分支)。
结果为:

[root@localhost day01_6.12]# ./test
 hello world!,pid: 3498,ppid: 3395
 hello world!,pid: 3499,ppid: 3498
 [root@localhost day01_6.12]#  gcc test.c
[root@localhost day01_6.12]# ./test
 hello world!,pid: 3505,ppid: 3395
 hello world!,pid: 3506,ppid: 3505


结果表示,先创建父进程,后创建子进程。也证明了:3.父子进程代码共享,数据各自开辟空间,私有一份采用(写时拷贝)——代码共享,数据私有

代码实现父子进程:

在fork()之前先处理父进程,在fork()之后,父子进程的处理顺序不一定,这个和调度有关。

  #include <stdio.h>
  #include <sys/types.h>
  #include <unistd.h>

  int main()
  {
      pid_t id = fork();
      if( id == 0  )// 子进程
      {
         while(1)
         {
             printf(" child do thing 1..... pid:%d ,ppid : %d \n",getpid(),getppid());
              sleep(1);
         }
     }
     else if ( id > 0 )// 父进程
     {
          while(1)
          {
             printf(" father do thing 2.... pid : %d ,ppid : %d \n ",getpid(),getppid());
             sleep(3);
          }
     }
      else
      {
         perror("fork");                                                                                                                                       

      }
     return 0;
  }

结果:

[root@localhost day01_6.12]# ./test
 father do thing 2.... pid : 3570 ,ppid : 3395 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
  father do thing 2.... pid : 3570 ,ppid : 3395 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
  father do thing 2.... pid : 3570 ,ppid : 3395 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
 child do thing 1..... pid:3571 ,ppid : 3570 
  father do thing 2.... pid : 3570 ,ppid : 3395 
 child do thing 1..... pid:3571 ,ppid : 3570 
^C
[root@localhost day01_6.12]# 

进程状态


僵尸状态:

也有可能出现内存泄漏(父进程对子进程僵尸状态不处理)
所以僵尸状态:1. 肯定会维护 2. 必须处理

这里我们可以看出来 ./a.out & 的作用就是a.out文件放在后台运行

test1.c:

 #include <unistd.h>
 #include <sys/types.h>

 int main()
 {
           while(1);
           return 0;                                                                            
 }
[root@localhost day01_6.12]# gcc test1.c
[root@localhost day01_6.12]# ./a.out

^C
[root@localhost day01_6.12]# ps aux | grep a.out
root      3614  0.0  0.0   5980   764 pts/1    S+   04:48   0:00 grep a.out
[root@localhost day01_6.12]# ./a.out &
[1] 3615
[root@localhost day01_6.12]# ./a.out
^C
[root@localhost day01_6.12]# ps aux | grep a.out
root      3615 91.2  0.0   1864   276 pts/1    R    04:48   0:17 ./a.out
root      3631  0.0  0.0   5980   744 pts/1    S+   04:48   0:00 grep a.out
[root@localhost day01_6.12]# 

修改进程状态

这里写图片描述
如果要恢复的话,18 SIGCONT 命令表示继续 即:kill -18 3615


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值