操作系统之进程!

进程和线程

进程:正在执行的应用程序,线程是轻量级的进程, 进程是分配资源的基础单位。

线程:轻量级进程,是程序执行的基本单位。

线程是进程的一部分,一个线程只能属于一个进程,一个进程可以有多个线程,但至少有一个线程。

每个进程都有独立的代码和数据空间(程序上下文),程序间的切换开销大。

  • 每个线程都有自己独立的运行栈和程序计数器(PC),线程间切换开销小。

互斥和同步区别

互斥:

是指在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时。

其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。

同步:

是指在不同进程之间的若干程序片断,它们的运行必须严格按照规定的 某种先后次序来运行。

这种先后次序依赖于要完成的特定的任务。

孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。

孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。

僵尸进程

一个进程使用fork创建子进程,如果子进程退出,而父进程没有调用wait或waitpid获取子进程的状态信息。

那么子进程的进程描述符仍然保存在系统中,这种进程(这个子进程)称之为僵尸进程。

如何清除僵尸进程?

改写父进程,为子进程收尸

具体做法是接收SIGCHLD信号,子进程死后会发送SIGCHLD信号给父进程。

父进程收到此信号后,执行waitpid()函数为其(子进程)进行收尸。

就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,默认处理为忽略,我们可以设置一个函数来对其进行处理。

如果把这个子进程(僵尸进程)的父进程杀掉,僵尸进程会变为孤儿进程,由init进程进行管理,init负责进行清理僵尸进程。

守护进程

守护进程就类似于一个后台进程。

进程状态

创建状态:

  • 进程由创建而产生。

就绪状态:

  • 进程已经准备好运行的状态,即进程已分配到除CPU以外所有的必要资源后,只要再获得CPU,便可立即执行。

运行状态:

  • 进程已经获取CPU,其进程处于正在执行的状态。

阻塞状态:

  • 正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)暂时无法继续执行的状态,即进程执行受到阻塞。

终止状态。

image-20231011210935893

进程通信

管道:

写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则。

管道这种通信方式效率低,不适合进程间频繁地交换数据。

消息队列:

消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制。

消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销。

因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程。

同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

共享内存:

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。

这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。

信号量:

用了共享内存通信方式,带来新的问题,那就是如果多个进程同时修改同一个共享内存,很有可能就冲突了。

  • 例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了 。

为了防止多进程竞争共享资源,而造成的数据错乱。

  • 所以需要保护机制,使得共享的资源,在任意时刻只能被一个进程访问。

正好,信号量就实现了这一保护机制。

信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。

信号:

信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程。

Socket:

要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。

操作系统执行一个程序的过程

操作系统检测类型是否是可执行文件。

创建进程,并且将可执行文件映射到该进程。

为该进程设置CPU上下文环境。

将代码和数据从磁盘读入内存。

运行过程中发生缺页异常则重复4。