多用户——多用户操作系统允许多个不同用户同时使用计算机的资源。操作系统必须确保均衡地满足各个用户的要求,他们使用的各个程序都具有足够且独立的资源,从而使一个用户的问题不会影响到整个用户群。Unix、VMS和大型机操作系统(如 MVS)是多用户操作系统的范例。
区分多用户操作系统和支持网络的单用户操作系统很重要。Windows 2000和Novell Netware均可以支持成千上万的网络用户,但操作系统本身并不是真正的多用户操作系统。系统管理员是Windows 2000或Netware的唯一“用户”。从操作系统的整体计划来看,网络支持和所有远程用户均可登录到网络,这些都属于由管理员用户运行的程序。
多用户是指系统资源可以被不同用户各自拥有使用,即每个用户对自己的资源(例如:文件、设备)有特定的权限,互不影响。因此多用户特性变成了衡量操作系统好坏的重要标准,如何保障用户公平的使用系统也成了系统设计者必须要考虑的问题。
----而不是同时使用,哈,
为了实现多用户特性,Linux系统将进程的生存周期划分为4种状态:
(1)进程正在用户态下执行;
(2)进程正在核心态下执行;
(3)进程未正在执行,但是它已准备好——一旦调度程序选中了它,它就可以投入运行。很多进程可以处于这一状态,而调度算法决定哪个进程将成为下一个执行的进程;
(4)进程正在睡眠。
4种状态的转换并不是任意的,而是一个有向图
因为任何时刻一个处理机仅能执行一个进程,所以至多有一个进程可以处在第一种状态和第二种状态。这两个状态相应于两种执行态:用户态和核心态。划分这两个级别主要是对系统提供保护,核心态可以执行一些特权指令和进入用户态,而用户态则不能。核心态与用户态的划分为Linux多用户特性提供了保证。
Linux中大部分的系统调用包含在Linux的libc库中,通过libc调用方法可以调用这些系统调用。因此,当用户进程需要使用系统资源时(如文件、显示器输出、打印机输出等),会通过调用标准C函数库中的函数实现相应功能(如open打开文件、printf进行显示器输出等)。系统调用的激活有两种方法:system_call函数和lcall7调用门(call gate)。还有一种syscall函数,是通过调用lcall7实现的,所以不算作一种特有的方法。对于内部代码来说,system_call是所有系统调用的入口点,lcall7用来支持iBCS2(Inter二进制兼容规范标准的版本2,这里不作讨论)。用户进程通过libc激活system_call,该libc会把自己希望传递的参数装载到CPU寄存器中,并触发0x80软件中断,即Int $0x80。这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数完成相应功能,等返回后,做一些系统检查,最后返回到进程(或到其他进程,如果这个进程时间用尽)。这便是用户进程进行系统调用的整体过程。
在一个分时系统中如Linux, 几个进程能同时进行,并且它们可能都进行了系统调用。内核将通过禁止任意的上下文切换和控制中断的发生保护核心态下运行的一致性。仅当进程从“核心态运行 ”状态转移到“在内存中睡眠”状态时,内核才允许上下文切换。在核心态下运行的进程不能被其他进程所抢占,因此内核有时被称为不可抢先的(non-preemptive),尽管内核也并不抢占用户态下的进程。由于处理系统调用之前的数据是准备好的,所以在系统调用的过程中不会出现死锁状态。又因为内核处于不可抢先状态,所以内核可保持它的数据结构一致性,从而解决了互斥(mutual exclusion)问题——保证在任何时刻至多一个进程执行临界区代码。
举个例子,设有三个用户进程A、B、C同时进行系统调用函数。进程睡眠的条件是临界区处于上锁状态。在任一时刻只能有一个进程在执行,它发现临界区是上了锁的,就在临界区变为开锁的状态的事件上等待。终于,临界区的锁解开了,所有的等待的进程被唤醒并进入“就绪”状态。内核最终选择一个进程(比如B)执行。进程B发现临界区处于开锁状态,于是为临界区上锁,并且继续执行。如果后来进程B在为临界区解锁之前再次去睡眠(例如等候I/O操作的完成),则内核能调度其他进程去运行。如果它选择了进程A,进程A发现临界区处于上锁状态,那么它就再次去睡眠。进程C也做同样的事情。最后,进程B醒来并为缓冲区解锁,允许进程A也允许进程C存 取缓冲区。因此,保证了至多一个进程能获得资源的存取。再此期间,进程的睡眠与唤醒过程应被考虑成“原子的”:一个进程瞬时地进入睡眠状态,并停留在那儿 直至它被唤醒。在它睡眠之后,内核调度另一个进程去运行,并切换后者的上下文。由此可见,临界区在任何时刻只有至多一个进程在执行。
总体说来Linux实现多用户特性的关键在于,将所有系统调用在将数据准备好后通过一个接口(system_call) 进入核心态,由核心态进行权限检查控制,并且保证资源的独占访问。在表面上看,系统调用就合其他的函数调用一样,只要结果符合预计的情况,应用程序就不能 确定是否真正使用了内核,从而达到核心态切换对用户层透明的目的。这样的过程也就保证了,每个用户进程对资源操作的互不影响。从而实现了Linux系统的多用户特性。
————————————————
版权声明:本文为CSDN博主「午夜听雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/White_Lee/article/details/84475325