父进程的返回值是子进程的进程ID,子进程的返回值是0(并不代表子进程的进程ID是0) 子进程和父进程并不共享存储空间,仅是父进程的副本。 这两个函数会对父子进程有一定的影响,当用vfork创建子进程时,子进程会先在父进程的地址空间运行(这跟fork不一样),如果子进程调用了exit就会把父进程的IO给关掉。 ? 对于调用了Wait和waitpid的进程会发生如下情况: (1)子进程还在运行,则阻塞 (2)如果子进程已终止,正在等待父进程获取其终止状态,则取得该进程的终止状态并立即返回 (3)如果没有子进程 sleep保证在打印父进程ID时第一个子进程已终止。 调用exec并不创建新进程,所以前后的进程ID并未改变。
进程通信 进程通信是指进程之间的信息交换 交换的信息量:一个状态或数值,上千个字节。 直接通信方式 发送进程直接把消息发送给目标进程 发送进程和接收进程都以显式方式分别提供对方的标识符 系统提供两条通信原语 Send(Receiver,message); Receive(Sender,message 系统运行期间始终存在 共享信箱 由某进程创建,创建时提供共享进程(用户)的名字 信息的拥有者和共享者,都有权从信箱中取走发送给自己的消息 信息通信时发送进程和接收进程的关系 一对一关系。 服务进程与多个用户进程之间进行交互,又称客户|服务器交互 一对多关系。一个发送进程与多个接收进程进行交互,使发送进程可用广播形式,向接收者发送消息。 多对多关系。 当一个进程正在对管道进行读/写操作时,另一进程必须等待。 (2)同步。当写(输入)进程把一定量的数据(如4K)写入管道后,便去睡眠等待,直到读(输出)进程取走数据后再把他唤醒。
进程 前置知识点 进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。 ..' % os.getpid()) # os.getpid获取当前进程的进程号 print('子进程将要结束...') Process创建的实例对象的常用方法: start():启动子进程实例(创建子进程) is_alive():判断进程子进程是否还在活着 join([timeout]):是否等待子进程执行结束,或等待多少秒 ': 20} 进程和线程的区别 进程是资源调度的基本单位,而线程是程序执行的基本单位 不同进程的地址空间是独立的,而同一进程中的线程之间共享 进程之间通信必须使用操作系统提供的进程间通信机制,同一进程中的各线程可以直接通信 如果改成: p = Pool(5) 就可以同时跑5个进程。 由于Pool的默认大小是CPU的核数,如果你不幸拥有8核CPU,你要提交至少9个子进程才能看到上面的等待效果。
进程概念 1.1 进程的概念 1.2 描述进程—PCB 2.进程的基本操作 2.1 查看进程 2.2 结束进程 2.3 查看进程的另一种方式(了解) 2.4 进程的系统调用(getpid) 2.5 常见进程调用(父进程、子进程) 2.6 通过系统调用创建进程-fork初识 3. 进程切换 本节目标 1. 进程概念 2. 进程的基本操作 3. 进程状态 4. 特殊进程 5. 进程优先级 6. 进程切换 那在还没有学习进程之前,就问大家,操作系统是怎么管理进行进程管理的呢? 很简单,先把进程描述起来,再把进程组织起来! 1. 进程概念 1.1 进程的概念 对于我们的了解来说,什么是进程呢? */ "S (sleeping)", /* 1 */ "D (disk sleep)", /* 2 */ "T (stopped)", /* 4 */ "t (tracing stop)", /* 8
进程通信: 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走 int pipe (int fd[2]); 通过匿名管道实现进程间通信的步骤如下: 父进程创建管道,得到两个⽂件描述符指向管道的两端 父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。 父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。 8 套接字通信 ---- 套接字( socket ) : 套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。 一个进程扮演客户端的角色,另外一个进程扮演服务器的角色,两个进程之间相互发送接收数据,这就是基于本地套接字的进程通信。
1.概念详解 1.运行&&阻塞&&挂起 内容基础:方框中的就是调度队列,是一个 双向队列,每一个元素是PCB+其对应的代码数据 1.运行 只要进程 在调度队列中,进程的状态就是运行(running) 设备队列中还有等待队列(wait queue) 如果某一个进程在调度队列中,而调度其需要从键盘上读取数据,但键盘上没响应,所以cpu会把这个进程从调度队列中拿下来,并把其链接到对应硬件的等待队列中。 2.进程状态 r表示running,表示正在运行 s表示浅睡眠,(例如输出一个字符只要1毫秒,但如果进程持续1(sleep(1))秒,那剩余的时间都处于浅睡眠时间,【可以被kill杀掉进程】 d表示深度睡眠 ,这类状态基本与硬盘数据交换有关【不可被kill杀掉进程】 Z表示僵尸状态,即子进程在运行完后不会直接消失,而是会先保留信息以留给父进程,这个状态就是僵尸状态【信息保留在PCB中】 那如果一直存在 3.小知识 进程退出了,内存泄漏的问题就不在了(例如malloc,进程结束后,申请的内存会被系统回收) 常驻内存例如:window系统,一些软件(开机后一直运行都如此,会导致卡机)
进程的状态和转换 进程是程序的一次执行。在这个执行过程中,有时进程正在被CPU处理,有时需要等待CPU服务,显然进程的状态是在不断变化的。 进程控制 进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新线程,撤销已有线程,实现线程状态转换等功能 简言之,进程控制就是要实现进程各个状态之间的转换 如何实现进程控制 原语 原语的特点是执行期间不允许中断 ,将运行环境保存到PCB,从PCB恢复运行环境) 所有进程控制原语一定会修改进程状态标志(因为所有进程控制原语一定修改进程状态) 剥夺当前运行进程的CPU使用权必然需要保存其运行环境(为后续该进程重新进入运行态 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程 终止其所有子进程 将该进程拥有的所有资源归还给父进程或操作系统 删除PCB 引起进程终止的事件 正常结束 异常结束(例如进程执行中出现bug) 外界干预 ,并更新其PCB 根据PCB恢复新进程所需的运行环境 引起进程切换的事件 当前进程的时间片结束 有更高优先级的进程到达 当前进程主动阻塞 当前进程终止 进程通信 进程通信指进程之间的信息交换 进程是系统分配资源的单位
大纲 线程与进程 线程与进程是操作系统里面的术语,简单来讲,每一个应用程序都有一个自己的进程。 操作系统会为这些进程分配一些执行资源,例如内存空间等。 有两种解决方案: 一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。 还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。 i)) # 生成线程列表 t1.append(t) for i in t1: # 运行线程 i.start() 输出的结果如下: 1 0 3 2 5 4 7 6 9 8 输出的结果: The number of CPU is:8 child p.name:Process-1 p.id11572 child p.name:Process-2 p.id8604 '【End】') 输出的结果如下: 主进程的 PID:7256 进程的名称:0 ;进程的PID: 1492 进程的名称:1 ;进程的PID: 12232 进程的名称:2 ;进程的PID: 4332 进程的名称
因此在一个 IBinder 对象写入 Parcel 对象然后发送到另一个进程时,另外那进程将这个 IBinder 对象发送回去时,原本进程接收到的 IBinder 对象和开始发送出去的是同一个引用。 ③系统在每个进程中都有一个处理事物的线程池,这些线程用于调度其他进程对当前进程的跨进程访问。 比如说进程 A 对进程 B 发起 IPC 时,A 中调用 transact() 的线程会阻塞。 比如,进程 A 向进程 B 发起 IPC,而进程 B 在其 Binder.onTransact() 中又用 transact() 向进程 A 发起 IPC,那么进程 A 在等待它发出的调用返回的同时,也会响应 这种机制可以让我们觉得到跨进程的调用与进程内的调用没什么区别,这是非常重要的。 ⑤在跨进程通信时,我们常常想要知道另外进程是否可用,IBinder 提供了三个检查的方法: transact() 当你调用的 IBinder 所在进程不存在时,会抛出 RemoteException
,保证多进程间的并发访问。 其中user_buffer_offset是虚拟进程地址与虚拟内核地址的差值,也就是说同一物理地址,当内核地址为kernel_addr,则进程地址为proc_addr=kernel_addr+user_buffer_offset BC请求码.png 重点说几个: BC_FREE_BUFFER:通过mmap()映射内存,其中ServiceMananger映射的空间大小为128K,其他Binder应用的进程映射的内存大小为8K- 那么当一个进程接收到这条命令时,该进程必须创建一条新的服务线程并注册该线程,在接下来的响应过程会看到合何时生成该响应嘛 BR_TRANSACTION_COMPLETE:当Client端向Binder驱动发送 一般地做法,需要Client端进程空间拷贝到内核空间,再由内核空间拷贝到Server进程,会发生两次拷贝。
如何查看进程状态 top 和 ps 是最常用的查看进程状态的工具 top 查看进程状态 S 列(也就是 Status 列)表示进程的状态 top 展示线程的五种状态 线程的第六种状态:T 或 t 就是 Stopped 或 Traced,表示进程处于暂停或跟踪状态 向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped) 再向它发送 SIGCONT 信号,进程又会恢复运行 (如果进程是终端里直接启动的,则需要你用 fg 命令,恢复到前台运行) 而当你用调试器(如:gdb)调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状态,这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行 线程的第七种状态:X Dead,表示进程已经消亡,所以不会再 top 或 ps 命令中看到它
Process 进程类型,用于创建和管理进程 Lock|RLock 进程互斥锁|重用锁,用于进程同步 Event 进程事件类型,用于进程同步 Condition 进程条件类型,用于进程同步 Queue 进程队列类型,用于多进程数据共享(不推荐,因为它多用于线程) Manager 进程管理类型,用于多进程数据共享(多进程管理中一般多使用该类型 p1=Person(参数) 共享数据问题,面向过程中的多进程并发模式:进程池: 多线程的操作模式下我们的全局变量是多个线程共享的,但是在多进程的情况下,进程本身就是一 个独立运行的程序,多进程意味着当前程序被执行了多次 ,每个进程中全局变量的数据都是互相独立的 在多进程并发处理的情况下如果用设置全局变量或者是传递参数的方式,并不能让数据被多个进程共享 函数执行并发操作时,每个进程都会单独拷贝一份当前进程的变量数据进行独立使用而不互相影响 pool = multiprocessing.Pool(2) # 定义 8 个任务,交给进程池处理 for i in range(8): pool.apply_async
顾名思义,DaemonSet 的主要功能是可让你在 K8s 集群中运行一个守护进程 Pod。DaemonSet 可确保在所有(或部分)工作节上点运行 Pod 的副本。 守护进程 Pod 具有以下特点: 它运行在 K8s 集群中的每个节点(大多数情况下)上 每个节点上只有一个这样的 Pod 当有新节点加入 K8s 集群时,就会在该新节点上自动创建 Pod 当一个节点被删除时 在每个节点上运行日志收集守护进程,例如 fluentd。 在每个节点上运行节点监控守护进程,例如 Prometheus node exporter。 K8s 系统守护程序集 事实上,K8s 本身就是使用 DaemonSet 来运行系统组件的。 这通常由守护进程集控制器DaemonSet Controller 处理。
在init.rc中定义了很多系统的守护进程,这里主要是做一些简单的介绍 一、uevent 负责相应uevent事件,创建设备节点文件: 代码在init.rc 550行 550service ueventd 577 disabled 578 user shell 579 group shell log 580 seclabel u:r:shell:s0 三、adbd abd的守护进程 610 onrestart restart surfaceflinger 611 onrestart restart drm 五、vold 负责完成系统USB存储卡等扩展存储自动挂载的守护进程 如果侦测到程序崩溃,debuggerd将把崩溃时的进程状态信息输出到文件和串口中,供开发人员分析和调试使用: 代码在init.rc 628行 628service debuggerd /system/ onrestart restart zygote 649 writepid /dev/cpuset/system-background/tasks 十、media: 系统多媒体部分的守护进程
supervisor介绍 1.1 简介 Supervisor是基于Python语言开发的一套的进程管理程序,它可以将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时支持自动重启。 1.2 工作原理 它主要是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。 也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和预警。 supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程。 听过这个,我们可以获得由主进程控制的子进程的状态,停止和启动子进程,并获得主进程的运行列表。 Web Server:通过web界面查看和控制进程状态。
文章目录 一、Android 进程优先级 二、前台进程 三、可见进程 四、服务进程 五、后台进程 六、空进程 一、Android 进程优先级 ---- Android 进程优先级 : ① 前台进程 > ② 可见进程 > ③ 服务进程 > ④ 缓存进程 > ⑤ 空进程 ; 关键优先级进程 : ① 活动进程 ; 高优先级进程 : ② 可见进程 , ③ 服务进程 ; 低优先级进程 : ④ 后台进程 , ⑤ 空进程 ; Android 系统中会尽量保证优先级高的进程的存在时间尽可能长 ; 如果资源不足 ( 这里的资源最主要的是内存 ) , 为了可以新建进程 , 以及重要进程的运行 , 系统会杀死一些低优先级进程 如弹出对话框 , 对话框是前台进程 , 后面被覆盖的 Activity 就变成了可见进程 ; 绑定在 可见 Activity 组件上的 Service 进程 , 也被称为可见进程 ; 可见进程也是很重要的进程 , 除非为了保证前台进程的运行 , 一般不会被回收 ; 四、服务进程 ---- ① 服务进程 : 调用 startService 方法启动的 Service 进程组件 , 就是服务进程 , 其没有与
nohup myprogram.sh & nohup 会返回运行进程的 PID。接下来我会更多地谈论 PID。 管理正在运行的进程 每个进程都有一个唯一的进程标识号 (PID) 。 这个数字是我们用来管理每个进程的。我们还可以使用进程名称,我将在下面演示。有几个命令可以检查正在运行的进程的状态。让我们快速看看这些命令。 PS 最常见的是 ps 命令。 00:00:00 [ksoftirqd/0] root 8 2 0 Aug18 ? 此外,如果以这种方式使用 top,每当这些进程中的一个停止或一个新进程开始时,top 都需要被告知有新的进程。 终止进程 KILL 有趣的是,没有 stop 命令。 SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8)
创建子进程规则是:子进程与父进程共享代码,写时拷贝 进程调用fork,当控制转移到内核中的fork代码后,内核做: 分配新的内存块和内核数据结构给子进程 将父进程部分数据结构内容拷贝至子进程 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) 设置进程ID:操作系统为每个新进程分配一个唯一的进程ID(PID),用于在系统中唯一标识该进程。 添加到进程列表:新创建的进程会被添加到系统的进程列表中,以便操作系统可以对其进行管理和调度。 更新进程列表:操作系统会从进程列表中移除已终止的进程。 5.进程等待 5.1必要性 在Unix/Linux系统中,当子进程退出时,它的进程描述符仍然保留在系统中,直到父进程通过某种方式获取其退出状态。 在父进程中,wait 方法常被用来回收子进程的资源并获取子进程的退出信息,从而避免产生僵尸进程。 wait 函数允许父进程等待其子进程结束,并可以获取子进程的退出状态。
1.进程创建 1.1 fork函数 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。 新进程为子进程,而原进程为父进程 #include <unistd.h> pid_t fork(void); 返回值:自进程中返回0,父进程返回子进程id,出错返回-1 进程调用fork,当控制转移到内核中的 fork代码后,内核做: 分配新的内存块和内核数据结构给子进程 将父进程部分数据结构内容拷贝至子进程 添加子进程到系统进程列表当中 fork返回,开始调度器调度 当一个进程调用fork之后,就有两个二进制代码相同的进程 ,父进程通过wait来获取该值 说明:虽然status是int,但是仅有低8位可以被父进程所用。 = wait(&st); if (ret > 0 && (st & 0X7F) == 0) { // 正常退出 printf("child exit code:%d\n", (st >> 8)
self) -> None: while 1: msg_from_client = self.connection.recv(1024).decode('utf8' encode('utf8') self.connection.send(msg_to_client) self.connection.close break # 设置自动回复消息 msg_to_client = '这是来自服务端的回复消息'.encode('utf8' 夯住循环""" while 1: msg_to_client = input('给服务端发消息>>>') socket_obj.send(msg_to_client.encode('utf8' )) msg_from_server = socket_obj.recv(1024).decode('utf8') print('msg_from_server:', msg_from_server