Lab#7 (CS500 OSD, Spring, 2016)
Due Date/Time:
Due Date/Time:
Before class, Tuesday July12, 2016 (Tuesday session)
Before class, ThursdayJuly14, 2016 (Thursday session)
Before class, Friday July15, 2016 (Friday session)
Before class, Saturday July16, 2016 (Saturday session)
Before class, Sunday July17, 2016 (Sunday session)
Turn in your lab results with screen shots to your graders, including the answers to the questions in red.
Each group assigned by graders just need to submit a report.
Note: You cannot earn this extra credit without finishing your individual case study. Submission after the deadline gets only partial credit.
Group number: ______
Student ID:______Name: ______
Student ID:______Name: ______
Student ID:______Name: ______
Student ID:______Name: ______
1
Summer 2015Silicon Valley University
Lab Description
Deadlock occurs when each of the four necessary condition occur. By ensuring that at least one of these conditions cannot hold, we can prevent the occurrence of a deadlock. The four necessary conditions are: 1) Mutual Exclusion. 2) Hold and Wait. 3) No Preemption. 4) Circular Wait.
In the lab, you will cause one of the conditions to occur, the “Hold and Wait” condition. Using mutexes to ensure mutual exclusion of the critical area for multiple threads, the “Hold and Wait” condition will occur when multiple resources (represented by the mutex) is held at the same time. Two threads will be created contending for the resources. You will clear the “Hold and Wait” condition and show that the deadlock no longer occurs.
Lab Procedure
1)Use vi editor to enter the C program below to file deadlock.c. The program will create two threads and cause a deadlock to occur when both threads try to acquire a resource without releasing an already held resource.
/* Includes */
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <sys/stat.h>
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
#include <zlib.h>
#include <fcntl.h>
#include <libgen.h>
#define _GNU_SOURCE
#include <getopt.h>
/* prototype for thread routine */
void handler1 ( void *ptr );
void handler2 ( void *ptr );
unsigned long computeCRC32( char *filename );
/* global vars */
/* semaphores are declared global so they can be accessed
in main() and in thread routine, here, the semaphore is used as a mutex.
*/
sem_t mutex1; /* semaphore */
sem_t mutex2; /* semaphore */
int counter = 0; /* shared variable */
void handler1 ( void *ptr )
{
int x;
int i, j;
int iloop = 5;
int isleep = 5;
unsigned long crc=0L;
x = *((int *) ptr);
printf("Thread %d: Waiting to enter critical region... Lock mutex1\n", x);
sem_wait(&mutex1); /* down semaphore */
/* START CRITICAL REGION */
printf("Thread %d: Now in critical region...\n", x);
printf("Thread %d: Incrementing Counter...\n", x);
counter++;
printf("Thread %d: Enter Sleep... Locked mutex1\n", x);
sleep(5); /* Sleep 5 seconds to allow Thread 2 to lock semaphore. */
printf("Thread %d: Exit Sleep... Lock mutex2\n");
sem_wait(&mutex2);
printf("Thread %d: New Counter Value: %d\n", x, counter);
printf("Thread %d: Exiting critical region...\n", x);
/* END CRITICAL REGION */
sem_post(&mutex1); /* up semaphore */
sem_post(&mutex2); /* up semaphore */
pthread_exit(0); /* exit thread */
return;
}
void handler2 ( void *ptr )
{
int x;
int i, j;
int iloop = 5;
int isleep = 5;
unsigned long crc=0L;
x = *((int *) ptr);
printf("Thread %d: Waiting to enter critical region... Lock mutex2\n", x);
sem_wait(&mutex2); /* down semaphore */
/* START CRITICAL REGION */
printf("Thread %d: Now in critical region...\n", x);
printf("Thread %d: Incrementing Counter...\n", x);
counter++;
printf("Thread %d: Enter Sleep... Locked mutex2.\n");
sleep(5); /* Sleep 5 seconds to allow Thread 1 to lock semaphore. */
printf("Thread %d: Exit Sleep... Lock mutex1.\n");
sem_wait(&mutex1);
printf("Thread %d: New Counter Value: %d\n", x, counter);
printf("Thread %d: Exiting critical region...\n", x);
/* END CRITICAL REGION */
sem_post(&mutex1); /* up semaphore */
sem_post(&mutex2); /* up semaphore */
pthread_exit(0); /* exit thread */
return;
}
int main( int argc, char *argv[] )
{
int ii[3] = {0, 1, 2};
pthread_t thread_a;
pthread_t thread_b;
sem_init(&mutex1, 0, 1); /* initialize mutex1 to 1 - binary semaphore */
/* second param = 0 - semaphore is local */
sem_init(&mutex2, 0, 1); /* initialize mutex2 to 1 - binary semaphore */
pthread_create (&thread_a, NULL, (void *) &handler1, (void *) &ii[0]);
pthread_create (&thread_b, NULL, (void *) &handler2, (void *) &ii[1]);
pthread_join(thread_a, NULL);
pthread_join(thread_b, NULL);
sem_destroy(&mutex1); /* destroy semaphore */
sem_destroy(&mutex2); /* destroy semaphore */
printf("Finished Main Process PID %d\n", (int)getpid());
exit(0);
} /* main */
2)Compile the C program:
gcc -lpthread –o deadlock deadlock.c
3)Execute on the command line,
(whoami); ./deadlock &
The main program creates two threads. Both threads uses the same resources. Each thread uses two semaphores to block the critical area and eventually the two threads create a deadlock.
The “&” places the command in background mode, so that the keyboard can still accept commands.
Q#1. Show the console output when you run the image. Take a snapshot of your screen. Answer: ______(1pt)
Your console should look like the following:
Thread 2: Waiting to enter critical region... Lock mutex2
Thread 2: Now in critical region...
Thread 2: Incrementing Counter...
Thread 2: Enter Sleep... Locked mutex2
Thread 1: Waiting to enter critical region... Lock mutex1
Thread 1: Now in critical region...
Thread 1: Incrementing Counter...
Thread 1: Enter Sleep... Locked mutex1
Thread 2: Exit Sleep... Lock mutex1
Thread 1: Exit Sleep... Lock mutex2
4)Use the following commands to show the threads are still running.
“ps -L” or “ps -L | grep deadlock”;
The “-L” is necessary to show the threads and the parent process. This was used in Lab4.
ps -L
PID LWP TTY TIME CMD
341 341 pts/2 00:00:00 deadlock parent process
341 342 pts/2 00:00:00 deadlock child thread1
341 343 pts/2 00:00:00 deadlock child thread2
491 491 pts/2 00:00:00 ps
16929 16929 pts/2 00:00:00 bash
Q#2. Are the threads still running? How can you tell if they are running or now? Take a snapshot of your screen. Answer: ______(1pt)
One of the ways to deal with a deadlock condition is to ignore a possible deadlock condition until it occurs, and then try to recover from the deadlock. The program in Step (1) should complete execution in 20 seconds. Since the program has not terminated, then we know the program is hung in some condition.
5)When processes are deadlocked, the only way to clear the deadlock condition is to send the SIGTERM (kill <pid>) or SIGKILL (kill -9 <pid>).
Q#3. Execute the “kill -9 <pid>” and process status command to show the deadlocked threads are terminated and no longer in the system.Take a snapshot of your screen. Answer: ______(1pt)
Your output should be similar to the following:
(whoami); ps -L
PID LWP TTY TIME CMD
4630 4630 pts/2 00:00:00 deadlock
4630 4631 pts/2 00:00:00 deadlock
4630 4632 pts/2 00:00:00 deadlock
4634 4634 pts/2 00:00:00 ps
16929 16929 pts/2 00:00:00 bash
kill -9 4630; Kill the process and threads
(whoami); ps -L
PID LWP TTY TIME CMD
4658 4658 pts/2 00:00:00 ps
16929 16929 pts/2 00:00:00 bash
[1]+ Killed ./deadlock
(whoami); ps –L Process and threads no longer in the system.
PID LWP TTY TIME CMD
4659 4659 pts/2 00:00:00 ps
16929 16929 pts/2 00:00:00 bash
6)Now edit the two threads, handler1( ) and handler2( ), to prevent the deadlock condition, “Hold and Wait”, from occurring. To prevent the “Hold and Wait” condition, any locked 1 must be released before another mutex can be locked. In thread1( ), make sure “mutex1” is released before “mutex2” is locked. In thread2( ), make sure “mutex2” is released before “mutex1” is locked.
In thread1 ( ),
. . .
printf("Thread %d: Enter Sleep... Locked mutex1\n");
sleep(5); /* Sleep 5 seconds to allow Thread 2 to lock semaphore. */
printf("Thread %d: Exit Sleep... Lock mutex2\n");
sem_post(&mutex1); /* up semaphore mutex1 before locking mutex2. */ < Add this code.
sem_wait(&mutex2);
. . .
In thread2( ),
. . .
printf("Thread %d: Enter Sleep... Locked mutex2\n");
sleep(5); /* Sleep 5 seconds to allow Thread 1 to lock semaphore. */
printf("Thread %d: Exit Sleep... Lock mutex1\n");
sem_post(&mutex2); /* up semaphore mutex2 before locking mutex1. */ < Add this code.
sem_wait(&mutex1);
. . .
7)Compile the C program again:
gcc -lpthread -o deadlock deadlock.c
(whoami); ./deadlock &
Q#4. Show the console output when you run the image. The process and threads should complete. You should see “Finished Main Process PID <pid>” on the console.
Take a snapshot of your screen. Answer: ______(1pt)
Thread 2: Waiting to enter critical region... Lock mutex2
Thread 2: Now in critical region...
Thread 2: Incrementing Counter...
Thread 2: Enter Sleep... Locked mutex2
Thread 1: Waiting to enter critical region... Lock mutex1
Thread 1: Now in critical region...
Thread 1: Incrementing Counter...
Thread 1: Enter Sleep... Locked mutex1
Thread 2: Exit Sleep... Lock mutex1
Thread 1: Exit Sleep... Lock mutex2
Thread 1: New Counter Value: 2
Thread 1: Exiting critical region...
Thread 2: New Counter Value: 2
Thread 2: Exiting critical region...
Finished Main Process PID 2436 Program finished. No deadlock
Summer 2015Silicon Valley University