ยง26.1โ€“26.2Why Use Threads? โ€ฆ An Example: Thread Creation

Part II OSTEP pp. 287โ€“291 ยท ~5 min read

  • thread control block
  • thread-local storage
  • parallelization

Part I built two grand illusions: many virtual CPUs, and a private address space apiece. The new abstraction lives inside one process: the thread โ€” more than one point of execution, multiple PCs fetching and executing, all within one shared address space.

Each thread looks remarkably like a process: its own PC, its own private registers; switching between threads means saving oneโ€™s state and restoring anotherโ€™s โ€” into a thread control block (TCB) rather than a PCB. One glorious difference: the address space stays put, so no page-table switch is needed. And one structural change โ€” the stack multiplies:

Figure 26.1 (left): the classic single-threaded address space โ€” one stack, at the bottom
Program Code โ“˜0KBHeap โ–พ โ“˜โ–ผ1KB(free)2KBStack โ–ด โ“˜โ–ฒ15KB16KB

click a region marked โ“˜ for details

Figure 26.1 (right): two threads, two stacks โ€” the tidy layout, ruined
Program Code0KBHeap โ–พ โ“˜โ–ผ1KB(free)2KBStack (2) โ–ด โ“˜โ–ฒ(free) โ“˜10KBStack (1) โ–ด โ“˜โ–ฒ15KB16KB

click a region marked โ“˜ for details

Anything stack-allocated lands on the relevant threadโ€™s stack โ€” thread-local storage .

26.1 Why Use Threads?

Two major reasons. Parallelism: with multiple CPUs and a big array to process, a thread per CPU turns one plodding pass into several concurrent ones โ€” parallelization , the standard route to speed on modern hardware. Avoiding blocked progress: while one thread waits on slow I/O (a message, a disk request, a page fault), the scheduler runs your other threads โ€” overlap of I/O and computation within a single program, exactly what multiprogramming achieved across programs. Hence thread-hungry web servers and DBMSs.

Could processes do both? Sure โ€” but threads share the address space, making data sharing natural; processes remain the sounder choice for logically separate tasks that shouldnโ€™t share.

26.2 An Example: Thread Creation

The humblest possible threaded program โ€” main creates two threads that print โ€œAโ€ and โ€œBโ€, then waits for both:

void *mythread(void *arg) {
    printf("%s\n", (char *) arg);
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t p1, p2;
    printf("main: begin\n");
    Pthread_create(&p1, NULL, mythread, "A");
    Pthread_create(&p2, NULL, mythread, "B");
    // join waits for the threads to finish
    Pthread_join(p1, NULL);
    Pthread_join(p2, NULL);
    printf("main: end\n");
    return 0;
}

Three threads in all: main, T1, T2. Now โ€” in what order do things happen? Step through all three answers:

Figures 26.3โ€“26.5: three legal executions of the SAME program โ€” the scheduler chooses
main
Thread 1
Thread 2
Trace 1 โ€” the children run when main waits
Trace 2 โ€” each child runs the moment it's created
Trace 3 โ€” "B" before "A"
step 1 / 21 ยท time flows downward

main: starts running; prints "main: begin"

Thread creation is like a function call that doesnโ€™t return to you first: the system creates a new execution stream for the routine, and it runs independently โ€” perhaps before create() returns, perhaps much later. What runs next is the schedulerโ€™s business, and while it presumably implements something sensible, it is hard to know what will run at any moment.

As you might also be able to tell: threads make life complicated. Computers are hard enough to understand without concurrency. With it โ€” as the next section demonstrates on a two-line loop โ€” it gets worse. Much worse.

Check yourself

1.A thread is 'very much like a separate process, except for one difference.' Which โ€” and what does it change about context switches?

2.What does the multi-threaded address space (Figure 26.1, right) do to the tidy single-stack layout?

3.The two major reasons to use threads:

4.In t0.c, main creates T1 ("A") then T2 ("B"), then joins both. Can "B" print before "A"?

5.When would you pick PROCESSES over threads for concurrent work?

5 questions