CS 111 Lecture 8 Scribe Notes - Spring 2013

Prepared by Ryan Hansberry, James Baumgarten, and Kasey Carrothers, for a lecture given by Paul Eggert at UCLA on March 25, 2013.



Leftovers from Last Lecture

Round Robin Scheduling:

"Polite" Round Robin

"Rude" Round Robin


Threads and Synchronization

The main software engineering problem with threads is how to do synchronization, that is synchronous access to memory. The default behavior of threads is unsynchronized access; they can all stomp on each others' memory.

Bill Gates's Bank Account

It's easy to write buggy, incorrect code when working with threads. Let's examine code that works with a bank account:

    long long int balance = 0; // measures pennies

    void deposit (long long int amt)
    {
       balance += amt;
    }
    
    void withdraw (long long int amt)
    {
        if (amt <= balance) {
            balance -= amt;
            return true;
        }
        return false;
    }
			

However, if this application is multithreaded, two threads might be able to interfere with each other.


Dealing with Threads

The volatile Keyword

Synchronization Primitives


Pipes and Critical Sections

How can we synchronize pipes? Let's consider the following code:

    enum { N = 1024 };

    // Assume this pipe will be used for 1 byte I/O
    struct pipe {
        char buf[N];
        unsigned r, w;
    };

    void writec(struct pipe *p, char c)
    {
        p->buf[p->w++%N] = c;
    }

    char readc (struct pipe *p)
    {
        return p->buf[p->r++%N];
    }
			

If a pipe is empty, readc() can either wait, or return an error. Let's look at the implementation for waiting:

The new readc() and writec():

    char readc (struct pipe *p)
    {
        while (pipe_empty(p)) continue;
        return p->buf[p->r++%N];
    }
    
    bool pipe_empty(struct pipe *p)
    {
        return p->w == p->r;
    }
    
    void writec(struct pipe *p, char c)
    {
        while (pipe_full(p)) continue;
        p->buf[p->w++%N] = c;
    }
    
    bool pipe_full(struct pipe *p)
    {
        return p->w - p->r == N;
    }
			

Problem: can have two writers at once. Let's consider locks to solve this...


Locks

Spinlocks

Spinlocks have an efficiency problem - they spin the CPU trying to get the lock. How about a new primitive that blocks if the resource is not available.

Mutex Locks