The problem with Processes (and IPC)

SIDE NOTE: There’s something we didn’t mention whenever we talked about processes in our previous lectures. It’s a concept known as a Context Switch.

Remember how OS presents a virtualized CPU to all processes? We as programmers don’t need to worry, in our code, about asking the OS to schedule our process for CPU time. But there IS SOME WORK involved in how the OS actually swaps processes around so their instructions can be executed by the CPU. The OS scheduler uses some dark magic to determine which processes should be run at which times… but when it IS time for a process to run, what happens?

Whenever one process uses up its allotted CPU time, the OS must send info from the next process to be executed to the CPU. The contents of this next process’ PCB (process control block!) and other related stuff must be swapped into the registers of the CPU. This is called a context switch, and it’s an expensive operation for a CPU to perform (or at least it is “relatively” expensive… it happens blazingly fast to us, but is a slower operation in terms of all the things your CPU can do).

OK, so the OS scheduler needs to perform context switches, what’s the big deal?

When we chatted about forking off child processes, we discussed how you might subdivide a problem into parts that can be worked on by different “computing units” so to speak, so you can fully leverage all of the cores of your machine’s CPU. We have multiple child processes and we use IPC (inter-process communication) so they can communicate to solve a shared problem. What are some issues that arise when we subdivide a problem this way?

  • We have to make many separate PROCESSES, each with their own additional baggage (PCB, address space, etc..)
  • We need a special mechanism to share memory between these processes (we used Shared Memory, but there are others)
  • The OS needs to context switch, which requires swapping stuff in and out of registers (and oftentimes cache!)

So… is there a better way for us to leverage the multi-core nature of our CPU without the baggage of IPC?

Threads

First, to define a thread: a thread is essentially a light-weight process. A more formal Wikipedia definition is “the smallest sequence of programmed instructions that can be managed by a scheduler”. But you can think of it as splitting off something almost like a sub-process. OK, that doesn’t tell us much… what are the actual characteristics of threads? How is it different from just forking off a new process? We’ll learn about this as we dive into the textbook and Mead’s notes today!

A warning about Multi-threading

You’ve likely heard about multi-threaded programs, but you’ve never made one yourself… so how do we do this? And WHY would we want to? First… let’s talk about some reasons why you would NOT want to multi-thread your programs!

First of all… proper multi-threading can be a complex, screwy endeavor that oftentimes is more dark magic than actual computer science.

Consider the nature of a single-threaded program. The program runs from top to bottom, in a more or less deterministic way. Sure, you branch this way and that, and you run loops and call functions… but ultimately it is easy enough to follow the flow of your program, especially if you’re using a debugger, or logging (printing) your program’s behavior.

Multi-threading turns everything on its head:

  • The behavior of your application is no longer deterministic, because the OS is in charge of scheduling which threads run at which time.
  • Since threads all share the same address space (minus their individual stacks) they can perform unexpected memory accesses, if programmed incorrectly
  • What if two threads, running simultaneously on two different cores, want to modify a single variable at the same time? What happens?
  • Multi-threading may SLOW DOWN your program compared to a single-threaded approach, if used incorrectly… it must be used when appropriate!
  • Even when multi-threading is used correctly, it can be tricky to maximize your program’s use of all the CPU cores available to you

There is a lot of power in the ability to multi-thread, but you’ve also opened a Pandora’s box of potential pitfalls. You must apply multi-threading with care, and with some thought for what kind of problem you’re intending to tackle.

With that being said… let’s take a look at the textbook and Mead’s notes :)

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-intro.pdf https://azrael.digipen.edu/~mmead/www/Courses/CS180/Threads-1.html