1. Tres problemas, tres papeles
En el tema 1 definimos el sistema operativo como el software que administra el hardware, ofrece servicios a los programas y los protege entre sí. Cada parte de esa definición responde a un problema concreto:
| El problema | El papel del sistema operativo | Nombre habitual |
|---|---|---|
| El hardware es complicado y cada dispositivo es distinto. | Ocultar los detalles detrás de operaciones simples y uniformes. | Máquina extendida |
| Hay pocos recursos y muchos programas que los quieren a la vez. | Decidir quién usa qué, cuándo y cuánto. | Gestor de recursos |
| Los programas tienen errores y algunos son malintencionados. | Aislar cada programa para que no dañe a los demás ni al sistema. | Protección |
Los dos primeros nombres describen el mismo software visto desde lados opuestos. Mirado desde arriba, desde un programa, el sistema operativo es una máquina más cómoda que la real. Mirado desde abajo, desde el hardware, es un administrador que reparte lo que hay. La protección atraviesa a ambos: sin ella, ni las abstracciones ni el reparto se podrían garantizar.
2. Problema 1: el hardware es difícil de usar
Tomemos una operación cotidiana: leer el contenido de un archivo. Desde un programa en C son tres pedidos:
int fd = open("notas.txt", O_RDONLY); /* abrir */
ssize_t n = read(fd, bloque, 4096); /* leer hasta 4096 bytes */
close(fd); /* cerrar */
El disco, sin embargo, no sabe qué es un archivo ni qué es un nombre. Un disco es una larga fila de bloques numerados, y lo único que entiende son órdenes del tipo «entrégame el bloque 7.340.112». Para cumplir esas tres líneas, el sistema operativo tiene que:
- Traducir el nombre. Recorrer los directorios hasta encontrar
notas.txty averiguar en qué bloques del disco está guardado, que pueden no ser consecutivos. - Comprobar permisos. Verificar que el usuario que ejecuta el programa puede leer ese archivo.
- Evitar trabajo. Mirar si esos bloques ya están en memoria por una lectura anterior, porque el disco es miles de veces más lento que la RAM.
- Hablar con el dispositivo. Armar la orden en el formato exacto que espera ese tipo de disco. Un disco NVMe, uno SATA y un pendrive USB se manejan con protocolos completamente distintos.
- Esperar sin bloquear la máquina. La lectura tarda; mientras tanto, la CPU debe atender a otros programas, y el disco avisará con una interrupción cuando termine.
- Tratar los errores. Reintentar si el dispositivo falla, y avisar al programa si no hay solución.
- Entregar los datos. Copiar los bytes a la memoria del programa, exactamente en la variable
bloque.
Si cada programa tuviera que hacer todo eso, escribir software sería carísimo y además frágil: un programa escrito para un modelo de disco no funcionaría con otro. El mismo problema se repite con el teclado, la pantalla, la red y cualquier otro dispositivo.
3. La solución: abstracciones
Una abstracción es una representación simplificada de algo complejo, que muestra solo lo necesario para usarlo y oculta cómo funciona por dentro.
Ya usas abstracciones todo el tiempo al programar: una función oculta sus instrucciones detrás de un nombre, y una lista oculta cómo se guardan sus elementos. El sistema operativo aplica la misma idea al hardware. Un archivo es una abstracción: una secuencia de bytes con nombre que se puede abrir, leer, escribir y cerrar. No existe en el disco como tal; es una construcción del sistema operativo sobre los bloques numerados.
Por eso se dice que el sistema operativo es una máquina extendida (o máquina virtual, en el sentido clásico del término): presenta a los programas una computadora imaginaria, más simple y más potente que la real. Estas son sus abstracciones principales:
| Recurso físico | Abstracción | Lo que el programa cree tener |
|---|---|---|
| CPU | Proceso | Un procesador dedicado, que ejecuta sus instrucciones sin interrupción. |
| Memoria RAM | Espacio de direcciones | Una memoria enorme, continua y privada. |
| Disco | Archivo y directorio | Datos con nombre, que perduran y crecen según haga falta. |
| Teclado, pantalla, terminal | Flujo de bytes | Un lugar del que se lee o en el que se escribe, como si fuera un archivo. |
| Tarjeta de red | Socket | Un canal directo con otro programa, esté donde esté. |
Las tres primeras filas son el esqueleto de cualquier curso de sistemas operativos, y también de esta ruta: los procesos se estudian en los cursos 5 y 6, la memoria en el 8 y los archivos en el 9.
Una buena abstracción no solo simplifica. También da portabilidad, porque el mismo programa funciona con hardware distinto sin modificarse, y permite que el hardware evolucione: cuando aparecieron los discos de estado sólido, ningún programa tuvo que cambiar, porque todos seguían viendo archivos.
4. Una abstracción en acción
El siguiente programa lee bytes de su entrada estándar (el descriptor 0) y los escribe en su salida estándar (el descriptor 1), hasta que no quede nada por leer:
#include <unistd.h>
int main(void)
{
char bloque[4096];
ssize_t leidos;
/* read devuelve cuántos bytes obtuvo; 0 significa "no hay más" */
while ((leidos = read(0, bloque, sizeof(bloque))) > 0)
write(1, bloque, leidos);
return 0;
}
El código no menciona teclados, discos ni pantallas. Y precisamente por eso sirve para todos ellos:
$ gcc copiar.c -o copiar
$ ./copiar # teclado → pantalla (Ctrl+D para terminar)
hola
hola
$ ./copiar < /etc/hostname # archivo → pantalla
mi-equipo
$ ./copiar < copiar.c > copia.c # archivo → archivo
$ date | ./copiar # otro programa → pantalla
dom 11 oct 2026 10:32:07 -03
En los cuatro casos el programa ejecuta las mismas instrucciones. Lo que cambia es a qué conectó la shell los descriptores 0 y 1 antes de iniciarlo: un teclado, un archivo en disco o la salida de otro programa. El kernel se ocupa de la diferencia. Esta uniformidad es una decisión de diseño heredada de Unix que suele resumirse como «todo es un archivo», y la retomamos en el tema 28.
Ocultar los detalles no los elimina. Para copiar, un archivo en un disco local y uno en una carpeta de red son iguales; pero el segundo puede tardar segundos o fallar a mitad de camino. Cuando un programa se comporta de forma inesperada, casi siempre es porque un detalle de la capa inferior se ha «filtrado» a través de la abstracción. Conocer lo que hay debajo, que es el objetivo de este curso, permite reconocerlo.
5. Problema 2: los recursos son escasos y compartidos
Una computadora de escritorio tiene, digamos, 8 procesadores, 16 GB de memoria, un disco y una tarjeta de red. En ese mismo equipo hay cientos de programas en ejecución, y cada uno fue escrito como si la máquina fuera suya. Alguien tiene que ordenar ese uso. Como gestor de recursos, el sistema operativo hace cuatro cosas:
- Asignar. Entregar a cada programa la CPU, la memoria o el espacio en disco que necesita, en el momento en que lo pide.
- Arbitrar. Resolver los conflictos cuando varios quieren lo mismo. Si dos programas envían documentos a la impresora al mismo tiempo, las páginas no pueden salir mezcladas.
- Llevar la cuenta. Saber en todo momento qué tiene cada programa: cuánta memoria ocupa, qué archivos abrió, cuánto tiempo de CPU consumió.
- Recuperar. Cuando un programa termina, aunque sea por un error y sin haber liberado nada, el sistema operativo recupera su memoria, cierra sus archivos y deja todo disponible para los demás.
El cuarto punto es fácil de pasar por alto y es esencial: gracias a él, un programa que termina mal no deja la máquina en peor estado que antes.
6. Repartir en el tiempo y en el espacio
Compartir un recurso entre varios se llama multiplexar, y solo hay dos formas de hacerlo:
- En el tiempo: los programas usan el recurso por turnos. Primero uno, después otro, luego otro, y se vuelve a empezar.
- En el espacio: el recurso se divide en partes y cada programa recibe una, que usa al mismo tiempo que los demás usan las suyas.
| Recurso | Cómo se reparte | Decisión que debe tomar el sistema operativo |
|---|---|---|
| CPU | En el tiempo | ¿A quién le toca ahora y por cuánto tiempo? |
| Memoria | En el espacio | ¿Qué zona recibe cada programa? ¿Qué se hace cuando no alcanza? |
| Disco | En el espacio | ¿En qué bloques se guarda cada archivo? |
| Impresora | En el tiempo | ¿En qué orden se imprimen los trabajos en cola? |
| Tarjeta de red | En el tiempo | ¿De qué programa es el próximo paquete que se envía? |
El reparto de la CPU se puede observar. En el siguiente ejemplo lanzamos dos bucles infinitos y, con taskset -c 0, obligamos a ambos a usar el mismo procesador (el número 0):
$ taskset -c 0 sh -c 'while :; do :; done' &
[1] 5120
$ taskset -c 0 sh -c 'while :; do :; done' &
[2] 5121
$ top # extracto; se sale con la tecla q
PID USER S %CPU %MEM TIME+ COMMAND
5120 diego R 50.0 0.0 0:07.31 sh
5121 diego R 49.7 0.0 0:07.29 sh
$ kill %1 %2 # detener los dos bucles
Cada bucle querría el 100 % del procesador, y ninguno contiene una sola línea para ceder el turno. Aun así, cada uno recibe la mitad: el kernel los interrumpe y alterna entre ellos decenas de veces por segundo. Cómo consigue quitarle la CPU a un programa que nunca la suelta es el tema del bloque 4.
7. La ilusión de la máquina propia
Abstracción y reparto se combinan en la técnica más característica de los sistemas operativos, la virtualización: tomar un recurso físico compartido y presentar a cada programa una versión virtual que parece exclusiva. Cada proceso cree tener su propia CPU y su propia memoria, y no necesita saber que existen otros.
El siguiente programa lo demuestra con la memoria. Tiene una variable global, contador, y en cada vuelta le suma un valor y muestra tres datos: su identificador de proceso (PID), la dirección de memoria de la variable y su contenido.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int contador = 0;
int main(int argc, char *argv[])
{
int paso = (argc > 1) ? atoi(argv[1]) : 1;
for (int i = 0; i < 4; i++) {
contador += paso;
printf("PID %d direccion %p contador = %d\n",
(int)getpid(), (void *)&contador, contador);
sleep(1);
}
return 0;
}
Lo compilamos y ejecutamos dos copias a la vez: una suma de a 1 y la otra de a 100.
$ gcc -no-pie ilusion.c -o ilusion
$ ./ilusion 1 & ./ilusion 100; wait
[1] 4211
PID 4211 direccion 0x404044 contador = 1
PID 4212 direccion 0x404044 contador = 100
PID 4211 direccion 0x404044 contador = 2
PID 4212 direccion 0x404044 contador = 200
PID 4211 direccion 0x404044 contador = 3
PID 4212 direccion 0x404044 contador = 300
PID 4211 direccion 0x404044 contador = 4
PID 4212 direccion 0x404044 contador = 400
Los dos procesos informan la misma dirección y, sin embargo, guardan valores distintos que no se pisan. Si esa dirección fuera una posición real de la memoria RAM, sería imposible. La explicación es que no lo es: cada proceso tiene su propio espacio de direcciones, y el kernel, con ayuda de la CPU, traduce la dirección 0x404044 de cada uno a una posición física diferente. Ninguno de los dos puede ver, ni siquiera nombrar, la memoria del otro.
-no-pie y los valores que verás
Por seguridad, Linux carga normalmente cada programa en direcciones elegidas al azar en cada ejecución. La opción -no-pie pide un ejecutable que se cargue siempre en el mismo lugar, para que la coincidencia quede a la vista. En tu equipo los PID y la dirección exacta serán otros; lo que importa es que la dirección sea la misma en las dos copias. Volvemos sobre esto en el tema 27.
8. Problema 3: los programas fallan
Compartir una máquina sería sencillo si todos los programas fueran correctos y honestos. No lo son: tienen errores, y algunos están escritos para hacer daño. Sin un árbitro, un solo programa defectuoso podría sobrescribir la memoria de otro, quedarse con la CPU para siempre o borrar el disco. El sistema operativo lo impide levantando barreras alrededor de cada recurso:
| Recurso | Amenaza | Barrera |
|---|---|---|
| Memoria | Leer o modificar datos de otro programa o del kernel. | Cada proceso solo accede a su espacio de direcciones. |
| CPU | Un bucle infinito que no deja ejecutar a nadie más. | Un temporizador devuelve el control al kernel periódicamente. |
| Archivos | Leer o borrar archivos de otro usuario. | Cada archivo tiene dueño y permisos, que el kernel verifica. |
| Dispositivos | Enviar órdenes directas al disco o a la red. | Solo el kernel, en modo privilegiado, puede hacerlo. |
Las barreras de la tabla no dependen de la buena voluntad de los programas: las hace cumplir la propia CPU, gracias a la distinción entre modo usuario y modo kernel que estudiamos en el tema 12. Podemos ponerlas a prueba. Este programa intenta escribir en una dirección de memoria que no le pertenece:
#include <stdio.h>
int main(void)
{
int *p = NULL; /* la dirección 0 no pertenece al programa */
printf("Antes de escribir\n");
*p = 42; /* intento de escritura fuera de su memoria */
printf("Esta linea nunca se ejecuta\n");
return 0;
}
$ gcc invasor.c -o invasor
$ ./invasor
Antes de escribir
Segmentation fault (core dumped)
$ echo $? # código con el que terminó el programa
139
Conviene leer este resultado como un éxito del sistema operativo. La CPU detectó el acceso inválido y avisó al kernel; el kernel finalizó el programa culpable, recuperó sus recursos e informó el motivo. La shell, los demás programas y el propio sistema siguieron funcionando como si nada. El código 139 es 128 + 11, donde 11 identifica la señal de violación de segmento.
La protección de archivos se comprueba con la misma facilidad:
$ cat /etc/shadow # archivo con las contraseñas cifradas
cat: /etc/shadow: Permission denied
El programa cat pidió abrir el archivo; el kernel comprobó quién lo pedía, vio que no tenía permiso y rechazó la llamada. cat se limitó a mostrar el error que recibió.
9. Objetivos en conflicto
Resolver los tres problemas a la vez obliga a hacer concesiones, porque los objetivos de un sistema operativo tiran en direcciones opuestas. No hay un diseño óptimo; hay equilibrios distintos para usos distintos.
| Se quiere… | …pero también | El conflicto |
|---|---|---|
| Eficiencia | Equidad | Lo más rápido es dejar terminar al programa en curso; lo más justo es alternar, y cada cambio cuesta tiempo. |
| Rendimiento | Protección | Cada verificación y cada cruce al kernel consume ciclos de CPU que el programa no aprovecha. |
| Respuesta inmediata | Trabajo total | Atender enseguida al usuario interrumpe tareas largas que rendirían más sin interrupciones. |
| Comodidad | Control | Una abstracción simple impide ajustar los detalles que oculta. |
Por eso existen sistemas operativos tan diferentes: uno para un teléfono privilegia la respuesta y la batería, uno para un servidor privilegia el trabajo total, y uno para el freno de un automóvil privilegia que cada acción ocurra dentro de un plazo. Los comparamos en el tema 23.
También conviene recordar que el sistema operativo tiene un costo propio: ocupa memoria, usa tiempo de CPU para tomar sus decisiones y hace que una llamada al sistema sea bastante más lenta que una llamada a una función común. Es el precio de las garantías que ofrece, y casi siempre vale la pena pagarlo.
10. Mecanismo y política
Un principio de diseño ayuda a ordenar todo lo anterior, y lo encontrarás en cada curso de esta ruta. Consiste en separar dos preguntas:
- El mecanismo responde cómo se hace algo. Por ejemplo: cómo se detiene un programa y se pone otro en la CPU.
- La política responde qué se decide hacer. Por ejemplo: cuál es el próximo programa que recibe la CPU.
Mantenerlos separados permite cambiar las decisiones sin reescribir la maquinaria. El mecanismo para alternar programas es el mismo en un teléfono y en un servidor; la política de a quién elegir es distinta. En la sección 6, la columna «decisión que debe tomar» de la tabla enumera políticas; los mecanismos que las hacen posibles son, justamente, lo que estudiamos en los bloques 3 y 4.
11. Resumen
- El sistema operativo responde a tres problemas: el hardware es difícil de usar, es escaso y compartido, y los programas no son fiables.
- Como máquina extendida, ofrece abstracciones: proceso para la CPU, espacio de direcciones para la memoria y archivo para el disco.
- Una abstracción simplifica, da portabilidad y permite que el hardware cambie sin tocar los programas; a cambio, oculta detalles que a veces se filtran.
- Como gestor de recursos, asigna, arbitra, lleva la cuenta y recupera lo que los programas dejan de usar.
- Los recursos se reparten en el tiempo (CPU, impresora) o en el espacio (memoria, disco).
- La virtualización da a cada proceso la ilusión de una CPU y una memoria propias: dos procesos pueden usar la misma dirección sin interferirse.
- La protección aísla a cada programa; un «Segmentation fault» o un «Permission denied» son el sistema operativo cumpliendo su trabajo.
- Los objetivos entran en conflicto, y separar mecanismo de política permite adaptar las decisiones a cada uso.
12. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Qué significa que el sistema operativo sea a la vez «máquina extendida» y «gestor de recursos»?
Son dos descripciones del mismo software. Para los programas es una máquina más simple que la real, hecha de abstracciones como archivos y procesos. Para el hardware es el administrador que reparte CPU, memoria y dispositivos entre quienes los piden.
2. El programa copiar funciona igual con el teclado y con un archivo. ¿Quién hace el trabajo distinto en cada caso?
El kernel. El programa siempre pide read sobre el descriptor 0; según a qué esté conectado ese descriptor, el kernel usa el controlador de la terminal o el sistema de archivos y el controlador del disco.
3. Clasifica: ¿la memoria RAM se multiplexa en el tiempo o en el espacio? ¿Y un único procesador?
La memoria, en el espacio: cada programa ocupa una zona distinta al mismo tiempo. Un procesador, en el tiempo: ejecuta un programa a la vez y alterna entre ellos con rapidez.
4. En ilusion, ¿cómo pueden dos procesos tener valores distintos en la misma dirección?
Porque la dirección que ve un programa es virtual, válida solo dentro de su espacio de direcciones. El sistema operativo y la CPU la traducen a una posición física distinta para cada proceso.
5. Un programa termina por un error sin liberar su memoria ni cerrar sus archivos. ¿Qué ocurre con esos recursos?
El sistema operativo los recupera. Como lleva la cuenta de todo lo que asignó a cada proceso, al finalizarlo libera su memoria y cierra sus archivos, sea cual sea la causa de la terminación.
6. «Elegir siempre el programa que lleva más tiempo esperando» ¿es un mecanismo o una política?
Una política: es una regla de decisión. El mecanismo es la maquinaria que permite detener un programa y poner en marcha el elegido, y es el mismo aunque se cambie la regla.
7. ¿Por qué se dice que «Segmentation fault» es una buena noticia para el resto del sistema?
Porque indica que el acceso inválido fue detectado y detenido antes de causar daño. Sin protección de memoria, esa escritura habría modificado en silencio datos de otro programa o del kernel.
Para practicar
- Ejecuta
copiarcon cinco orígenes y destinos distintos. Prueba./copiar < /proc/cpuinfo: ¿de qué «archivo» está leyendo? - Repite el experimento de
tasksetcon tres bucles en el mismo procesador y predice el porcentaje de CPU de cada uno antes de mirartop. - Compila
ilusion.csin-no-pie, ejecútalo varias veces y observa cómo cambia la dirección. - Para cada recurso de tu equipo (CPU, memoria, disco, red, pantalla), escribe qué abstracción ofrece el sistema operativo y si se reparte en el tiempo o en el espacio.