Lecture 5 - Threads and Process Synchronization
Bill Gates: Your Internet ad was brought to my attention, but I can't figure out what,
if anything, Compuglobalhypermeganet does, so rather than risk competing
with you, I've decided simply to buy you out.
Homer: I reluctantly accept your proposal!
Bill Gates: Well everyone always does. Buy 'em out, boys! [Gates' lackeys trash the room.]
Homer: Hey, what the hell's going on!
Bill Gates: Oh, I didn't get rich by writing a lot of checks! [insane laughter]
- Bill Gates buys Homer's Internet company, in "Das Bus," The Simpsons episode 5F11.


Agenda

Announcements

  • Friday's CS Colloquium, 4 more students discuss their summer work experiences: Rob Gonzalez, Jeremy Redburn, Chris Cyll, Josh Ain.
  • Final Words on CPU Scheduling

    Things to consider:

  • Multiprocessor systems - how do we do CPU scheduling when we have more than one CPU? More on this later in the semester.
  • Real-time systems - which approaches can be used when a small delay for some processes is unacceptable?
  • How can we compare the algorithms and approaches?

  • Deterministic modeling - consider a set of processes and see what happens with various algorithms. Our Gantt charts were an example.
  • Queueing models - take a mathematical approach. Given mathematical descriptions of the kind of processes and the underlying system, determine expected performance. This would likely be a major topic in a graduate level operating systems course.
  • Implementation - try it out on a real system. May be impractical, but it's the best test, of course.
  • Simulation - devise a model and simulate it. See Project 1.
  • Threads/Lightweight Processes

    Those of you who have taken or TA'ed for the objectdraw version of CS 134 here know about Java threads. You may have called them ActiveObjects. These gave you the ability to have your programs doing more than one thing at a time. Such a program is called multithreaded.

    Threads are a stripped-down form of a process:

  • a task or process can contain multiple threads
  • Threads share process context
  • Threads are asynchronous
  • Threads have less context than processes
  • Threads can be created/destroyed at a lower cost than processes
  • Threads cooperate to do a process in parallel with (relatively) fine granularity of parallelism
  • Threads are well-suited to symmetric multiprocessors (SMPs).
  • Threads can be useful even in single-user multitasking systems:

  • Foreground and background work: one thread to deal with user input, another to update display, etc such as in a spreadsheet or word processor.
  • Asynchronous processing: auto-save features, background computation.
  • Speed execution: compute with one batch of data while reading another. Your process can be in I/O and on the CPU at the same time!
  • Organizing programs: cleaner and more elegant program design.
  • Sample thread application: NFS server. With heavyweight processes, each request from the network would require a heavyweight process creation. This is expensive since many requests result in frequent, short-duration processes being created and destroyed. With multithreading, one NFS server task can exist, and threads created within the task for each request ("pop-up" threads). There is less overhead, plus if there are multiple CPUs available, threads can be assigned to each for faster performance.

    User Threads vs. Kernel Threads

    Threads may be implemented within a process (in "user space," also often referred to as "userland") or by the kernel (in "kernel space").

    With user threads, the kernel sees only the main process, and the process itself is responsible for the management (creation, activation, switching, destruction) of the threads.

    With kernel threads, the kernel takes care of all that. The kernel schedules not just the process, but the thread.

    There are significant advantages and disadvantages to each, and Tanenbaum describes these. Some systems provide just one, some systems, such as Solaris, provide both.

    One big thing is that with user threads, it is often the case that when a user thread blocks (such as for I/O service), the entire process blocks, even if some other threads could continue. With kernel threads, one thread can block while others continue.

    pthreads, POSIX threads We saw how to use fork() to create threads in Unix. There is a POSIX standard interface to create threads.

    An online tutorial is available here

    A google search for "pthread tutorial" yields many others.

    Instead of creating a copy of the process like fork(), create a new thread, and that thread will call a function within the current task.

    The basic pthread functions are:

    Simplest form:

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                       void * (*start_routine)(void *),
                       void *arg);
    
    int pthread_join(pthread_t thread, void **status);
    
    void pthread_exit(void *value_ptr);
    

    A pthread "hello, world" program is here.

    To compile under Solaris (bullpen), need to link with the pthread library by adding -lpthread to the link line.

    To compile under FreeBSD (lab machines), need to pass a special flag -pthread to the compiler and linker to tell it to use the reentrant C library libc_r.a.

    We said that threads share more context than processes. To see this, try out this example.

    Cooperating Processes

    An Independent process is not affected by other running processes.

    Cooperating processes may affect each other, hopefully in some controlled way.

    Why cooperating processes?

  • information sharing
  • computational speedup
  • modularity or convenience
  • It's hard to find a computer system where processes do not cooperate. Consider the commands you type at the Unix command line. Your shell process and the process that executes your command must cooperate. If you use a pipe to hook up two commands, you have even more process cooperation (See Project 2).

    For the processes to cooperate, they must have a way to communicate with each other. Two common methods:

  • shared variables - some segment of memory accessible to both processes
  • message passing - a process sends an explicit message that is received by another
  • For now, we will consider shared-memory communication. We saw that threads, for example, share their global context, so that is one way to get two processes (threads) to share a variable.

    Producer-Consumer Problem

    The classic example for studying cooperating processes is the Producer-Consumer problem.

    One or more produces processes is "producing" data. This data is stored in a buffer to be "consumed" by one or more consumer processes.

    The buffer may be:

  • unbounded - We assume that the producer can continue producing items and storing them in the buffer at all times. However, the consumer must wait for an item to be inserted into the buffer before it can take one out for consumption.
  • bounded - The producer must also check to make sure there is space available in the buffer.
  • Next class, we consider solutions to the bounded buffer problem..