Introduction to concurrency using threads

Review

INFOprocess calls fork()
  • New PCB (process control block) and address space.
  • New address space is a copy of the entire contents of the parent’s address space (up to fork).
  • Resources (file pointers) that point to parent’s resources.
  • In general, time consuming.
INFOprocess context switch
  • Save A’s registers to A’s kernel stack.
  • Save A’s registers to A’s PCB.
  • Restore B’s registers from B’s PCB.
  • Switch to B’s kernel stack.
  • Restore B’s registers from B’s kernel stack.
  • In general, time consuming.
EXAMPLEA web server
  • A process listens to requests.
  • When a new request comes in, a child process is created to handle this request.
  • Multiple requests can be handled at the same time by different child processes.
  • What is the problem?
1
2
3
4
5
6
7
8
while (1) {
	  int sock = accept();
  if (0 == fork()) {
    handle_request();
    close(sock);
    exit(0);
  }
}

Thread

A new abstraction for running processes
  • A normal process is a running program with a single point of execution, i.e, a single PC (program counter).
  • A multi-threaded program has multiple points of execution, i.e., multiple PCs.
  • Each thread is very much like a separate process, except for one difference:
    • All threads of the same process share the same address space and thus can access the same data.
State of a single thread
  • Each thread has its own PC.
  • Each thread has its own private set of registers for computation.
  • Context switching is still needed.
  • Threads use Thread Control Blocks (TCP) to store their execution states.
  • Context switching is similar to that of processes, except for:
    • Thread context-switching keep the same address space (i.e., no need to switch out the page table).
EXAMPLEWeb server using thread
1
2
3
4
5
6
7
8
9
10
11
12
13
int global_counter = 0;
web_server() {
  while (1) {
    int sock = accept();
    thread_create(handle_request, sock);
  }
}

handle_request(int sock) {
  process request;
  ++global_counter;
  close(sock);
}
API: POSIX threads (pthreads)
  • Standardized C language thread programming API.
  • pthreads specifies the interface of using threads, but not how threads are implemented in OS.
  • Different implementations include:
    • kernel-level threads,
    • user-level threads, or
    • hybrid
  • pthread_create
  • pthread_join

Hands on: say hello to my little threads …

1
2
mkdir ~/concurrency
cd ~/concurrency
1
2
3
4
gcc -o thread_hello thread_hello.c -lpthread
./thread_hello 1
./thread_hello 2 
./thread_hello 4

The problem with threads

DANGEREdward Lee (2006). The Problem with Threads. Computer 39(5).

From a fundamental perspective, threads are seriously flawed as a computation model because they are wildly nondeterministic… The programmer’s job is to prune away that nondeterminism. We have developed tools to assist in the pruning: semaphores, monitors, and more modern overlays on threads offer the programmer ever more effective pruning. But pruning a wild mass of brambles rarely yields a satisfactory hedge. To offer another analogy, a folk definition of insanity is to do the same thing over and over again and expect the results to be different. By this definition, we in fact require that programmers of multithreaded systems be insane. Were they sane, they could not understand their programs.

Challenge