system
Given the following post, respond as if you're commenting on Reddit:
human
ELI5: Kernels (computing)

I hear they're important, but I've never heard a good explanation of them.
gpt
The kernel is the heart of an operating system.  The most basic kernel does very few things.  It manages and restricts access to memory, it manages processes and threads, it manages communication between processes, and controls access to the disks.

1) Memory access.  In order to run more than one program at a time, you need to have space in memory set aside for each program to use.  Each program needs to be restricted to using it's own space in memory, and *only* it's own space.  If you don't do this, badly behaving programs will damage data from other programs.  Commonly, each program won't even know the memory used for other processes exists.

2) Process management. In order to run more than one program at once, you need some code to keep track of all the programs, and to schedule time for each of them to use the processor.

In most desktop and server operating systems, this is done in some semblance of fairness, allowing each program to request time on the processor, and rotating through each program in turn to give roughly equal access to each, though a process can give up some of it's time voluntarily.

There are other ways to do this, like real-time computing, which allows programs to request hard deadlines, a time that they *must* be finished processing by.  This is often used in some kind of control system, where the computer must take input, and process it quickly enough to respond to whatever is happening in the real world.

There's also the fact that most modern computers have more than one processor available.  This can allow programs to split themselves into multiple pieces that are more or less independent, in order to run in parallel to each other.  Making sure that programs actually gain performance out of this takes some adjustments to how you schedule processes.

3) Communication between processes.  Often, programs will be divided into smaller units that perform some task, and then hand a result off to another part of the same program.  Or you want to be able to take advantage of multiple processors available, and run some of your code on each.  Or your code uses some standard library or device driver in order to perform a standard task, or to talk to some piece of hardware.

To split your code into multiple processes, you need a way to communicate.  In kernel land, this mostly takes the form of semaphores, pipes, message queues and shared memory.

Semaphores let two or more programs control how they execute in relation to each other.  It's essentially a flag that each program can raise and lower to let the other process know they've reached some specific point in their code.  They're commonly used to let parallel processes share some common resource without stomping all over the other processes using it.  If the flag is up, one program is using it, and any other programs using the same resource shouldn't touch it until the flag goes down.

Pipes are common in the Unix based world.  They take the output from one program, and feed it into another.  Usually, they're very temporary, only existing long enough to transition from one program to another.

Message queues are used for longer term communication.  One program can put data into a queue, and when another related program gets it's turn on the processor, it can read from the queue.  Messages stack up in sequence, so the reading program reads them in the same order they were sent.

Shared memory is actually just a careful breaking of a concern from 1).  Normally, each program should be kept separate in memory, so they don't stomp all over each other.  But, if they want to communicate large pieces of data, the kernel can set aside another piece of memory that they both have access to.  Each program can read and write to this spot in memory when it's their turn.

4) Disk access.  Programs need to have access to disk, and while it's less critical than memory and processor time that it's shared equally, you also don't want programs stomping all over each other's data.

The more important point is actually that disk access is slow.  In computing time scales, it's glacially slow.  It's so slow that it would be a really stupid idea for the processor to be idle while waiting for a response to come back when it could run through a few more turns for other programs in the time it would have just been sitting there.

The kernel controls this.  When a program requests disk input or output, it will send the request off to the disk, then put the program in a waiting state.  When the response comes back, it triggers an interrupt, a special circuit in the processor that stops everything and loads up the kernel to process the response.  The kernel then loads whatever program was waiting for the response, and lets it finish what it was doing as if the processor *was* sitting idle instead of letting other programs cut in line.

---

You'll notice that all of these functions for the kernel have something in common.  They're all about letting you run more than one program at a time.  Before we'd written any operating system's and kernel's, running one program at a time is just how using a computer worked.  You'd manually load a program into memory, manually start it processing, and the computer would do only that one thing until it had finished and gave you some output.

Also, it should be pointed out that modern kernels do more than just these four things.  They typically come with all kinds of additional tools to make writing programs easier.  A modern kernel is a one-stop shop for every programming shortcut you might need.

But, if you wanted to write something that would be called a kernel, at a minimum, you'd want it to do these four things.