Name: ________________________________ Login: _____________

Comp111 Midterm Exam
Oct 27, 2011 - open books and notes

No electronic devices of any kind allowed, including cellphones, calculators, pagers, etc. Please turn these off before beginning the exam.

Please show all work on these pages. Make sure that your work for each problem is clearly marked. These pages will be graded and returned electronically, like exercises.

  1. (20 points) One student wrote the following code as an initial experiment in assignment 3:
     
    int status; 
    void reaper(int sig) { 
        wait(&status); 
        fprintf(stderr, "reaped\n"); 
    } 
    main() { 
        signal(SIGCHLD, reaper); 
        if (fork()) { 
    	wait(&status); 
    	fprintf(stderr, "done\n"); 
        } else { 
    	execl("./a.out", "./a.out", NULL); 
        } 
    } 
    
    The student complained that "signal handling didn't work" because the "done" message printed but the "reaped" message did not. What actually caused this behavior?

    Name: ________________________________ Login: _____________

  2. (20 points) The following implementation of a bounded buffer does not work as expected. What is wrong with the implementation, what behavior results from the error, and how could you fix the problem without adding more locks or semaphores?
     
    void init() { 
        sem_init(&used,0,0);       	   // nothing is used
        pthread_mutex_init(&enqueue_mutex,NULL);   // mutex unlocked
        pthread_mutex_init(&dequeue_mutex,NULL);   // mutex unlocked
    } 
    int full() { return (end+1)%SIZE==begin; } 
    void enqueue(char c) { 
        if (!full()) { 
    	pthread_mutex_lock(&enqueue_mutex); 
    	queue[end]=c; end=(end+1)%SIZE;
    	pthread_mutex_unlock(&enqueue_mutex); 
        } else { 
    	fprintf(stderr,"Buffer is already full\n"); 
        } 
        sem_post(&used);        // tell dequeue there is more input
    } 
    char dequeue() { 
        char out; 
        sem_wait(&used);        // wait for input
        pthread_mutex_lock(&dequeue_mutex); 
        out = queue[begin]; begin=(begin+1)%SIZE; 
        pthread_mutex_unlock(&dequeue_mutex);  
        return out; 
    } 
    

    Name: ________________________________ Login: _____________

  3. Consider the following resource allocation matrix:
    Requested Granted Deficit
    R1R2R3R4 R1R2R3R4 R1R2R3R4
    P10 0 0 0 - P10 0 0 0 = P10 0 0 0
    P22 1 1 1 P21 1 1 1 P21 0 0 0
    P33 2 2 2 P32 2 2 2 P31 0 0 0
    Totals
    R1 R2 R3 R4
    3 3 3 3
    1. (10 points) Is this a safe situation? Why or why not?









    2. (5 points) Could use of the Banker's algorithm result in this situation? Why?









    3. (5 points) For a system in this situation, is there any way that P3's request for resource 1 could decrease by 1? Why?

    Name: ________________________________ Login: _____________

  4. (20 points) Write a code fragment that arranges to write output to a file "foo.txt" when printing to stdout. Explain each step.

    Name: ________________________________ Login: _____________

  5. (20 points) You are writing a producer/consumer music player. The producer reads music files from disk, while the consumer plays them on an audio card. Compare the following implementations: What are the pros and cons of each potential solution?

    Name: ________________________________ Login: _____________

  6. (Advanced; 10 points extra credit) The following thread routine:
    int i=0; 
    void * thread(void *v) { 
       int j; 
       for (j=0; j<1000; j++) i++; 
    } 
    
    has the behavior that occasionally, for n copies running concurrently, i can be less than 1000*n. Explain exactly why.