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