KEMBAR78
Manual Tutorial SDD | PDF | Computer File | Computer Programming
0% found this document useful (0 votes)
35 views32 pages

Manual Tutorial SDD

Dr. Shrinivas D. Desai is a professor at BVB College of Engineering with a strong academic background, including a Ph.D. from VTU Belagavi. The document outlines various exercises related to UNIX commands, process control, race conditions, and inter-process communication. It also includes programming examples and explanations of concepts such as zombie and orphan processes, as well as thread creation and management.

Uploaded by

srushtik1013
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views32 pages

Manual Tutorial SDD

Dr. Shrinivas D. Desai is a professor at BVB College of Engineering with a strong academic background, including a Ph.D. from VTU Belagavi. The document outlines various exercises related to UNIX commands, process control, race conditions, and inter-process communication. It also includes programming examples and explanations of concepts such as zombie and orphan processes, as well as thread creation and management.

Uploaded by

srushtik1013
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

DR.

SHRINIVAS D
DESAI
PROFESSOR, SOCSE, KLE Tech. HUBLI

PROFILE
He is serving in BVB College of
Engineering from May 2000. He
earned his UG degree from KUD
Dharwad, Masters from JNNCE
Shimoga, and Ph.D from VTU
Belagavi.

He loves teaching with Active


learning classes, He is honored
b=with state ambassador during
Mission10X at WIPRO Bengaluru.

CONTACT
PHONE:
9845275066

EMAIL:
sd_desai@kletech.ac.in
Contents
Profile .................................................................................................................................................................................................. 1
Contact.............................................................................................................................................................................................. 1
Exercise 1: Demonstration of UNIX commands related to processes, files and memory ................................................................ 3
Exercise 2: Implementation of Process control activities, Zombie and Orphan processes, (fork,wait,exit,vfork) ......................... 6
Exercise 3: Race Condition ................................................................................................................................................................... 12
Exercise 4: Implementation of Inter Process Communication (IPC): Pipes and FIFO ..................................................................... 17
Exercise 5: Implementation Critical Section Problem by Semaphore .............................................................................................. 21
Exercise 6: Program to Simulate Deadlock Situation.......................................................................................................................... 24
Exercise 7: Program to Simulate Dining Philosophers Problem.......................................................................................................... 26
Exercise 8: Program on File Locking..................................................................................................................................................... 30
Exercise 1: Demonstration of UNIX commands related to processes,
files and memory
OS / Tools:
Ubuntu OS
Online GDB
JS Linux

Linux System Calls:

ls
ls - alF
mkdir, rmdir,lpr rm.txt,mv(move or rename of file)
cp, cat, cd, mv, grep
To create a file:
vi test1.text
press i to insert word
press ESC and type :wq

mv

grep
The grep filter searches a file for a particular pattern of characters, and displays all lines that
contain that pattern. The pattern that is searched in the file is referred to as the regular expression
(grep stands for globally search for regular expression and print out).
Syntax:

grep [options] pattern [files]

Options Description
-c : This prints only a count of the lines that match a pattern
-h : Display the matched lines, but do not display the filenames.
-i : Ignores, case for matching
-l : Displays list of a filenames only.
-n : Display the matched lines and their line numbers.
-v : This prints out all the lines that do not matches the pattern
-e exp : Specifies expression with this option. Can use multiple times.
-f file : Takes patterns from file, one per line.
-E : Treats pattern as an extended regular expression (ERE)
-w : Match whole word
-o : Print only the matched parts of a matching line,
with each such part on a separate output line.

-A n : Prints searched line and nlines after the result.


-B n : Prints searched line and n line before the result.
-C n : Prints searched line and n lines after before the result.

chmod
File permissions can be viewed using the ls command:
ls -l filename.txtCopy
-rw-r--r-- 12 linuxize users 12.0K Apr 8 20:51 filename.txt
|[-][-][-]- [------] [---]
|| | || | |
|| | || | +-----------> 7. Group
|| | || +-------------------> 6. Owner
| | | | +--------------------------> 5. Alternate Access Method
| | | +----------------------------> 4. Others Permissions
| | +-------------------------------> 3. Group Permissions
| +----------------------------------> 2. Owner Permissions
+------------------------------------> 1. File Type
Copy

The first character shows the file type. It can be a regular file (-), directory (d), a symbolic link (l), or any other special type of
file.

The next nine characters represent the file permissions, three triplets of three characters each. The first
triplet shows the owner permissions, the second one group permissions, and the last triplet shows
everybody else permissions. The permissions can have a different meaning depending on the file
type.

In the example above (rw-r--r--) means that the file owner has read and write permissions (rw-), the
group and others have only read permissions (r--).
Each of the three permission triplets can be constructed of the following characters and have a
different effects, depending on whether they are set to a file or to a directory:

Read - The file is not readable. You cannot view the file contents.

r The file is readable.

Write - The file cannot be changed or modified.

w The file can be changed or modified.

Execute - The file cannot be executed.

x The file can be executed.

To edit a C program

nano filename.c

To save and exit: Ctrl+x, Press Y

To compile and run: gcc filename.c


./a.out
Exercise 2: Implementation of Process control activities, Zombie and
Orphan processes, (fork,wait,exit,vfork)
To know PID and Parent PID

1) Run following program and guess, which is Parent ID and which is Child ID?

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int main(int argc, char* argv[])


{
int id = fork();
printf("%d\n”, getpid());
return 0;
}

localhost:~# gcc file1.c


localhost:~# ./a.out
129
130

2) Now run this and build family tree with PID numbers

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int main(int argc, char* argv[])


{
int id = fork();
printf("Current ID: %d\n, parent ID: %d\n",getpid(),getppid());
return 0;
}

localhost:~# gcc file1.c


localhost:~# ./a.out
Current ID: 121
, parent ID: 61
Current ID: 122
, parent ID: 121
fork
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int main()
{ fork( ); printf(“\n hello OSSP”); }

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int main()

{
fork();
fork();
fork();
printf("hello\n");
return 0;
}

vfork

#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int glob = 6;

int main(void)
{
int var;
pid_t pid;

var =88;
/* printf("Before vfork\n");*/
pid = fork();

if (pid ==0) {
glob++;
var++;
_exit(0);
}

/* Parent continues here*/


printf("pid = %d, glob = %d, var = %d\n",getpid(), glob, var);
exit(0);
}

If we run this code with “fork” then OS may schedule either parent or child process. And
Parent may run first hence global and local variable values are printed without update

If we run this code with “vfork” then OS will first schedule child. Where global and local
variable gets updated. But child exits abnormally

Now parent will run and display updated value.

Thats the difference...


“vfork guarantees that the child runs first, until the child calls exec or exit.”
zombie and orphan
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
pid_t pid;
pid = fork();

if (pid ==0){
printf("I am child and my PID is %d\n",getpid());
printf("My parent PID is %d\n", getppid());
}
else {
sleep(10);
printf("I am parent and my PID is %d\n", getpid());
printf("My child PID is %d\n", pid);
}
return 0;
}

Wehen we run this making parent to sleep for 10 sec, and then run ps command we get
localhost:~# gcc file1.c
localhost:~# ./a.out &
localhost:~#ps

PID TTY TIME CMD


173 tty1 00.00.00 a.out <defunct>

Orphan

https://www.youtube.com/watch?v=DYDHNL_AImo

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
pid_t pid;
pid = fork();
if (pid ==0){
sleep(2);
printf("I am child and my PID is %d\n",getpid());
printf("My parent PID is %d\n", getppid());
}
else {
printf("I am parent and my PID is %d\n", getpid());
printf("My child PID is %d\n", pid);
}
return 0;
}

Wait()
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
pid_t p;
printf("before fork\n");
p=fork();
if(p==0)//child
{
printf("I am child having id %d\n",getpid());
printf("My parent's id is %d\n",getppid());
}
else//parent
{
wait(NULL);
printf("My child's id is %d\n",p);
printf("I am parent having id %d\n",getpid());
}
printf("Common\n");
}

If we run above code without “wait(NULL)” then output may be either from
child or from parent or mix.

wait() system call is added to the parent section of the code. Hence, the
moment processor starts processing the parent, the parent process is
suspended because the very first statement is wait(NULL). Thus, first, the
child process runs, and the output lines are all corresponding to the
child process. Once the child process finishes, parent resumes and prints
all its printf() statements. The NULL inside the wait() means that we are
not interested to know the status of change of state of child process.

We should not call wait() in child process, because in that case child
will be waiting for its child to complete first.. and that may not be the
case.

Program to use wait system call || wait() || Program - YouTube

Viva questions on wait() system call


Q1. Can we use wait() to make the child process wait for the parent process to finish?
Q2. What does the wait() system call return on success?

Practice Program for wait() system call


Q1. Write a program to create two child process. The parent process should wait for both the child to finish.
Q2. Create a parent-child relationship between two process. The parent should print two statements:
A) its own PID
B) PID of its child
The child should print two statements:
C) its own PID
D) PID of its parent
Make use of wait() in such a manner that the order of the four statements A, B, C and D is:
A
C
D
B
You are free to use any other relevant statement/printf as you desire and their order of execution does not matter.
Exercise 3: Race Condition
To visualize this, thread creation and its understanding is essential

Program to create threads in linux. Thread prints 0-4 while the main process prints 20-24

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void *thread_function(void *arg);
int i,j;
int main() {
pthread_t a_thread; //thread declaration

pthread_create(&a_thread, NULL, thread_function, NULL);


//thread is created
pthread_join(a_thread, NULL); //process waits for thread to finish . //Comment this line to see the
difference
printf("Inside Main Program\n");
for(j=20;j<25;j++)
{
printf("%d\n",j);
sleep(1);
}
}

void *thread_function(void *arg) {


// the work to be done by the thread is defined in this function
printf("Inside Thread\n");
for(i=0;i<5;i++)
{
printf("%d\n",i);
sleep(1);
}
}

Note: To compile any program which involves creation of thread(s) use pthread library (lpthread)
Suppose the above program is named “Thread.c”, then to compile write
$gcc thread.c -lpthread
To run, the command remains same
$./a.out

Output
0
1
2
3
4
Inside Main Program
20
21
22
23
24

Rerun the program by commenting pthread_join(a_thread, NULL);


And see the result

How it works?
pthread_create() creates a new thread which starts to execute thread_function. This function
creates a loop which prints 0-4. The sleep function makes the thread go to sleep after each digit is
printed. pthread_join() makes the main function wait until the newly created thread finishes its
execution. So the control returns to the main function only when the thread finishes. Then the main
function prints “Inside Main program” and executes the loop from 20-24.

How a thread returns a value to the main process?


pthread_exit() is used to return a value from the thread back to the main process. The program
below shows this. The program also shows how to pass value to a thread from the main process.

Homework:
How a thread returns a value to the main process?
pthread_exit() is used to return a value from the thread back to the main process. The program
below shows this. The program also shows how to pass value to a thread from the main process.

Program 2: Write a Program to create a thread. The thread prints numbers from zero to n, where
value of n is passed from the main process to the thread. The main process also waits for the thread
to finish first and then prints from 20-24.

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
void *thread_function(void *arg);
int i,n,j;
int main() {
char *m="5";
pthread_t a_thread; //thread declaration
void *result;
pthread_create(&a_thread, NULL, thread_function, m); //thread is created
pthread_join(a_thread, &result);
printf("Thread joined\n");
for(j=20;j<25;j++)
{
printf("%d\n",j);
sleep(1);
}
printf("thread returned %s\n",(char *)result);
}
void *thread_function(void *arg) {
int sum=0;
n=atoi(arg);
for(i=0;i<n;i++)
{
printf("%d\n",i);
sleep(1);
}
pthread_exit("Done"); // Thread returns "Done"
}

How to pass multiple values to a thread using structure?


Program 3: Program to create a thread. The thread is passed more than one input from the main
process. For passing multiple inputs we need to create structure and include all the variables that are
to be passed in this structure.
#include<stdio.h
#include<pthread.h>
struct arg_struct { //structure which contains multiple variables that are to passed as input to the
thread
int arg1;
int arg2;
};
void *arguments(void *arguments)
{
struct arg_struct *args=arguments;
printf("%d\n", args -> arg1);
printf("%d\n", args -> arg2);
pthread_exit(NULL);
}
int main()
{
pthread_t t;
struct arg_struct args;
args.arg1 = 5;
args.arg2 = 7;
pthread_create(&t, NULL, arguments, &args);
//structure passed as 4th argument
pthread_join(t, NULL); /* Wait until thread is finished */
}
Note: Just as above we can also pass an array to a thread.
race condition
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
void *fun1();
void *fun2();
int shared=1; //shared variable
int main()
{
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, fun1, NULL);
pthread_create(&thread2, NULL, fun2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2,NULL);
printf("Final value of shared is %d\n",shared); //prints the
last updated value of shared variable
}

void *fun1()
{
int x;
x=shared;//thread one reads value of shared variable
printf("Thread1 reads the value of shared variable as
%d\n",x);
x++; //thread one increments its value
printf("Local updation by Thread1: %d\n",x);
sleep(1); //thread one is preempted by thread 2
shared=x; //thread one updates the value of shared variable
printf("Value of shared variable updated by Thread1 is:
%d\n",shared);
}

void *fun2()
{
int y;
y=shared;//thread two reads value of shared variable
printf("Thread2 reads the value as %d\n",y);
y--; //thread two increments its value
printf("Local updation by Thread2: %d\n",y);
sleep(1); //thread two is preempted by thread 1
shared=y; //thread one updates the value of shared variable
printf("Value of shared variable updated by Thread2 is:
%d\n",shared);
}
When we execute this program, two threads thread1 and thread2 try to
access and modify the value of “shared” variable concurrently. This
leads to race condition. Hence final value of shared will be either 2
or 0 depending on who wins the race...
This shall be solved by using mutesx or semaphore.

gcc filename.c -lpthread


./a.out
Exercise 4: Implementation of Inter Process Communication (IPC):
Pipes and FIFO
To understand IPC, its essential to understand “popen”

#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

int main()
{
FILE *rd;
char buffer[50];
sprintf(buffer,”KLE TECH HUBLI”);
rd = popen(“wc – c”,”w”);
fwrite(buffer,sizeof(char),strlen(buffer),rd);
pclose(rd);
}

PIPES and FIFOs

PIPES in single window


#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
int fd[2],n;
char buffer[100];
pid_t p;
pipe(fd); //creates a unidirectional pipe with two end fd[0]
and fd[1]
p=fork();
if(p>0) //parent
{
printf("Parent Passing value to child\n");
write(fd[1],"hello\n",6); //fd[1] is the write end of the pipe
}
else // child
{
printf("Child printing received value\n");
n=read(fd[0],buffer,100); //fd[0] is the read end of the pipe
write(1,buffer,n);
}
}
IPC by FIFO (Named PIPEs)
//Program1: Creating fifo/named pipe ( //Program2: Writing to a fifo/named pipe ( //Program 3: Reading from the named
mkfifo.c ) sender.c ) pipe ( 3.c )
#include<unistd.h> #include<unistd.h>
#include<stdio.h> #include<stdio.h> #include<stdio.h>
#include<sys/types.h> #include<fcntl.h> #include<fcntl.h>
#include<sys/stat.h> int main() int main()
int main() { {
{ int res,n; int res,n;
int res; char buffer[100];
res = res=open("fifo1",O_WRONLY);
mkfifo("fifo1",0777); //creates a res=open("fifo1",O_RDONLY);
named pipe with the name fifo1 write(res,"Message",7);
printf("named pipe printf("Sender n=read(res,buffer,100);
created\n"); Process %d sent the printf("Reader
} data\n",getpid()); process %d started\n",getpid());
} printf("Data
received by receiver %d is:
%s\n",getpid(), buffer);
}

How to run
Command Remark / Output
vi mkfifo.c Edit the main program and save
gcc mkfifo.c ➢ Named pipe created
./a.out
ls fifo1 ➢ Fifo1
ls –l fifo1 ➢ prwxr – xp......

vi sender.c Edit sender program and save


gcc –o sender sender.c
./sender No display (Bcoz Blocked mode)
Ctrl+c

vi receiver.c
gcc –o receiver receiver.c
./receiver No display (Bcoz Blocked mode)
Ctrl+C
./sender & ./receiver Running sender in background and
Receiver in foreground
#include<stdio.h> //pipe_creation.c //rightTerminal.c
void main() //leftTerminal.c
#include<stdio.h>
#include<stdio.h> #include<fcntl.h>
{ #include<fcntl.h> #include<string.h>
int f1,f2; #include<string.h> #include<stdlib.h>
f1 = #include<stdlib.h> void main()
mkfifo("pipeA",066 void main() {
6); { char str[256]="start";
char str[256]="start"; int fifo_read,fifo_write,i;
if(f1<0) int fifo_write,fifo_read,i; while(strcmp(str,"end")!=0)
printf("\npipeA {
was not created"); while(strcmp(str,"end")!=0)
else { fifo_read=open("pipeA",O_RDONL
printf("\npipeA Y);
created"); fifo_write= if(fifo_read<0)
open("pipeA",O_WRONLY); printf("\nError opening read
f2 = if(fifo_write<0) pipe");
mkfifo("pipeB",0666 printf("\nError opening else
); pipe");
else {
if(f2<0) {
printf("\npipeB printf("\nEnter text:\n"); read(fifo_read,str,255*sizeof(char)
was not created"); );
else i=0; close(fifo_read);
printf("\npipeB is while (1) printf("\n%s",str);
created\n"); { }
} scanf("%c",&str[i]);
if (str[i] == '\n')
break; fifo_write=open("pipeB",O_WRONL
i++; Y);
} if(fifo_write<0)
// scanf("%s",str); printf("\nError opening write
pipe");
write(fifo_write,str,255*sizeof(char) else
); {
close(fifo_write); printf("\nEnter text:\n");
} i=0;
while (1)
{
fifo_read=open("pipeB",O_RDONL
Y); scanf("%c",&str[i]);
if(fifo_read<0) if (str[i] == '\n')
break;
printf("\nError opening write i++;
pipe"); }
else
{ write(fifo_write,str,255*sizeof(char)
);
read(fifo_read,str,255*sizeof(char) close(fifo_write);
); }
close(fifo_read); }
printf("\n%s",str); }

}
}
}
Exercise 5: Implementation Critical Section Problem by Semaphore
Program for process synchronization using semaphores

Q. Program creates two threads: one to increment the value of a shared variable and second to decrement
the value of the shared variable. Both the threads make use of semaphore variable so that only one of the
threads is executing in its critical section

#include<pthread.h>
#include<stdio.h>
#include<semaphore.h>
#include<unistd.h>
void *fun1();
void *fun2();
int shared=1; //shared variable
sem_t s; //semaphore variable
int main()
{
sem_init(&s,0,1); //initialize semaphore variable - 1st argument is address
of variable, 2nd is number of processes sharing semaphore, 3rd argument is the
initial value of semaphore variable
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, fun1, NULL);
pthread_create(&thread2, NULL, fun2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2,NULL);
printf("Final value of shared is %d\n",shared); //prints the last updated
value of shared variable
}
void *fun1()
{
int x;
sem_wait(&s); //executes wait operation on s
x=shared;//thread1 reads value of shared variable
printf("Thread1 reads the value as %d\n",x);
x++; //thread1 increments its value
printf("Local updation by Thread1: %d\n",x);
sleep(1); //thread1 is preempted by thread 2
shared=x; //thread one updates the value of shared variable
printf("Value of shared variable updated by Thread1 is: %d\n",shared);
sem_post(&s);
}
void *fun2()
{
int y;
sem_wait(&s);
y=shared;//thread2 reads value of shared variable
printf("Thread2 reads the value as %d\n",y);
y--; //thread2 increments its value
printf("Local updation by Thread2: %d\n",y);
sleep(1); //thread2 is preempted by thread 1
shared=y; //thread2 updates the value of shared variable
printf("Value of shared variable updated by Thread2 is: %d\n",shared);
sem_post(&s);
}

The final value of the variable shared will be 1. When any one of the threads executes the wait operation the
value of “s” becomes zero. Hence the other thread (even if it preempts the running thread) is not able to
successfully execute the wait operation on “s“. Thus not able to read the inconsistent value of the shared
variable. This ensures that only one of the thread is running in its critical section at any given time. The
output is as shown below. The working of the program is also discussed in detail.

Output

Process synchronization using semaphore

How it works?
The process initializes the semaphore variable s to ‘1’ using the sem_init() function. The initial value is set to
‘1’ because binary semaphore is used here. If you have multiple instances of the resource then counting
semaphores can be used. Next, the process creates two threads. thread1 acquires the semaphore variable
by calling sem_wait(). Next, it executes statements in its critical section part. We use sleep(1) function to
preempt thread1 and start thread2. This simulates a real-life scenario. Now,
when thraed2 executes sem_wait() it will not be able to do so because thread1 is already in the critical
section. Finally, thread1 calls sem_post() function. Now thread2 will be able to acquire s using sem_wait().
This ensures synchronization among threads.

Practice Program
Q. Write a program to achieve synchronization between multiple threads. The threads try to acquire a
resource that has two instances

Viva questions on Program for Process Synchronization using


Semaphores
Q1. What is the initial value of the semaphore variable?
Q2. Why we use pthread_join() function in the above program?
Q3. Why is the fourth parameter in pthread_create() NULL?
Q4. What is the significance of using sleep(1) function in the functions fun1() and fun2()?
Q5. How to use counting semaphores?
Q6. What will be the initial value of the semaphore variable if there are 5 instances of the resource?

https://youtu.be/MMfWwailXw0
Exercise 6: Program to Simulate Deadlock Situation
Deadlock in operating system is a situation which occurs when a process or thread enters a waiting state
because a resource requested is being held by another waiting process, which in turn is waiting for another
resource held by another waiting process. In a deadlock state a process is unable to change its state(waiting)
indefinitely because the resources requested by it are being used by another waiting process.

Setup

To simulate deadlock in the system we will create the above shown situation.

P1 and P2 will be represented by two thread one and two.


The two resources R1 and R2 will be represented by the two lock
variables first_mutex and second_mutex
First thread one will acquire lock first_mutex and then thread two will acquire lock second_mutex.
Hence, both the threads have acquired one resource each. Next, thread one will try to acquire
lock second_mutex while the second thread, thread two will try to acquire lock first_mutex. Since the
resources are already occupied by the other thread, both the threads will get into a deadlock.

Note: You must know how to create Threads to understand this program

Program to simulate Deadlock Using C in Linux using Mutex Locks and threads

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *function1();
void *function2();
pthread_mutex_t first_mutex; //mutex lock
pthread_mutex_t second_mutex;

int main() {
pthread_mutex_init(&first_mutex,NULL); //initialize the lock
pthread_mutex_init(&second_mutex,NULL);
pthread_t one, two;
pthread_create(&one, NULL, function1, NULL); // create thread
pthread_create(&two, NULL, function2, NULL);
pthread_join(one, NULL);
pthread_join(two, NULL);
printf("Thread joined\n");
}

void *function1( ) {

pthread_mutex_lock(&first_mutex); // to acquire the resource/mutex lock


printf("Thread ONE acquired first_mutex\n");
sleep(1);
pthread_mutex_lock(&second_mutex);
printf("Thread ONE acquired second_mutex\n");
pthread_mutex_unlock(&second_mutex); // to release the resource
printf("Thread ONE released second_mutex\n");
pthread_mutex_unlock(&first_mutex);
printf("Thread ONE released first_mutex\n");
}

void *function2( ) {
pthread_mutex_lock(&second_mutex);
printf("Thread TWO acquired second_mutex\n");
sleep(1);
pthread_mutex_lock(&first_mutex);
printf("Thread TWO acquired first_mutex\n");
pthread_mutex_unlock(&first_mutex);
printf("Thread TWO released first_mutex\n");
pthread_mutex_unlock(&second_mutex);
printf("Thread TWO released second_mutex\n");

https://youtu.be/XVZMxXBBqtc
Exercise 7: Program to Simulate Dining Philosophers Problem
In this experiment we are going to understand the C program implementing the solution to the Dining
Philosopher Problem. The Dining Philosopher Problem states that there are five philosophers which do two
thinks: think and eat. They share a table having a chair for each one of them. In the center of the table there
is a bowl of rice and the table is laid with 5 single chopsticks (Refer Figure Below).

When a philosopher thinks, he does not interact with others. When he gets hungry, he tries to pick up the
two chopsticks that are near to him. For example, philosopher 1 will try to pick chopsticks 1 and 2. But the
philosopher can pickup only one chopstick at a time. He can not take a chopstick that is already in the hands
of his neighbour. The philosopher stars to eat when he has both his chopsticks in his hand. After eating the
philosopher puts down both the chopsticks and starts to think again.

Solution to Dining Philosopher Problem


Represent each chopstick with a semaphore. Each philosopher first picks up the left chopstick and then the
right chopstick using the wait() operation each semaphore. After eating he puts down the chopsticks by
using the signal() operation on each chopstick.

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<unistd.h>
sem_t chopstick[5];
void * philos(void *);
void eat(int);
int main()
{
int i,n[5];
pthread_t T[5];
for(i=0;i<5;i++)
sem_init(&chopstick[i],0,1);
for(i=0;i<5;i++){
n[i]=i;
pthread_create(&T[i],NULL,philos,(void *)&n[i]);
}
for(i=0;i<5;i++)
pthread_join(T[i],NULL);
}
void * philos(void * n)
{
int ph=*(int *)n;
printf("Philosopher %d wants to eat\n",ph);
printf("Philosopher %d tries to pick left chopstick\n",ph);
sem_wait(&chopstick[ph]);
printf("Philosopher %d picks the left chopstick\n",ph);
printf("Philosopher %d tries to pick the right chopstick\n",ph);
sem_wait(&chopstick[(ph+1)%5]);
printf("Philosopher %d picks the right chopstick\n",ph);
eat(ph);
sleep(2);
printf("Philosopher %d has finished eating\n",ph);
sem_post(&chopstick[(ph+1)%5]);
printf("Philosopher %d leaves the right chopstick\n",ph);
sem_post(&chopstick[ph]);
printf("Philosopher %d leaves the left chopstick\n",ph);
}
void eat(int ph)
{
printf("Philosopher %d begins to eat\n",ph);
}

How it works?
Now let us understand how the code works

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<unistd.h>
sem_t chopstick[5];
void * philos(void *);
void eat(int);
sem_t chopstick[5] is used to declare 5 semaphore variable, one for each of
the five chopsticks. Next, two are the prototypes for functions defined below.
In the main() function there are three for loops. The first loop is used to
initialize each semaphore variable with initial value to 1. The second for
loop is used to create five threads which will act as the five philosophers.
The third for loop uses the pthread_join function which makes the parent
program wait for each of the thread to finish.
Next is the philos function. The philos function when called by each thread
receives the same value as the thread number. For example if thread one runs,
the variable ph in the philos function is assigned the value n. This is done
because each philosopher n before eating will pick two chopstick, n and
(n+1)%5.
Next, the sem_wait function is used on the left chopstick first
sem_wait(&chopstick[ph]);
If successful, the thread executes the sem_wait function on the right chopstick
sem_wait(&chopstick[(ph+1)%5]);
These two operations are equivalent to picking the left chopstick and then the right chopstick. If both these
operations are successful this means that the philosopher is able to pick both the chopsticks and hence will
start to eat by calling the eat() function. After eating both the chopsticks are release by using
the sem_post() function.

Output
Here’s a sample output. Your output might differ each type you run the program. This is because the
sequence of execution of threads will be different. Try to understand the output below and then relate it
with what you get.
Here philosopher(thread) 0 tries to eat first. So, it tries to pick the left chopstick, which it does. Then the
right one. Since it picks both the chopstick so philosopher 0 starts to eat. Now, refer to the image at the
beginning of the post. If philosopher 0 starts to eat this means chopstick 0 and 1 are busy hence, philosopher
1 and 4 can not eat until philosopher 0 puts down the chopsticks. Read the output now, next philosopher
wants to eat. It tries to pick the left chopstick (i.e. chopstick 1) but is not successful because chopstick 1 is
already with philosopher 0. Similarly, you can understand the rest of the output.

https://youtu.be/XVZMxXBBqtc
Exercise 8: Program on File Locking

File Locking

This program will write lock a sample.txt file. As it is write lock, when
try to execute the same program in another window, it wont lock. Only when
the first program (first window) releases lock, the second window will apply
lock

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
char buf[100];
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len= 0;
fl.l_pid = getpid();

printf("P1 Applying\nwrite lock");


int fd = open("sample.txt", O_WRONLY|O_APPEND);
if (fd == -1)
{
perror("Unable to open file: ");
exit(EXIT_FAILURE);
}
printf("Press Enter to try to get lock -");
getchar();
printf("Locking...\n");
if (fcntl(fd, F_SETLKW, &fl) == -1)
{
perror("fcntl caused some error: ");
exit(EXIT_FAILURE);
}
printf("Locked\n");
strcpy(buf,"we are appending file\n");
if (write(fd,buf,strlen(buf))<0)
{
perror("Problem in writing to file");
exit(1);
}
printf("Press Enter to release lock -");
getchar();
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1)
{
perror("fcntl caused some error: ");
exit(EXIT_FAILURE);
}
printf("Unlocked.\n");
close(fd);
return 0;
}

==========================================================

This program will read lock a sample.txt file. As it is read lock, when try
to execute the same program in another window, it will lock. This is because
two reader shall operate on file simultaneously

include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
char buf[100];
struct flock fl;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len= 0;
fl.l_pid = getpid();
printf("Applying\nread lock");
int fd = open("sample.txt", O_RDONLY);
if (fd == -1)
{
perror("Unable to open file: ");
exit(EXIT_FAILURE);
}

printf("Press Enter to try to get lock -");


getchar();
printf("Locking...\n");

if (fcntl(fd, F_SETLKW, &fl) == -1)


{
perror("fcntl caused some error: ");
exit(EXIT_FAILURE);
}
printf("Locked\n");

int flag=read(fd,buf,100);
if(flag<0){
printf("Error occured while reading\n");
exit(1);
}
printf("Read file content:\n");
printf("%s\n",buf);

printf("Press Enter to release lock -");


getchar();
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1)
{
perror("fcntl caused some error: ");
exit(EXIT_FAILURE);
}
printf("Unlocked.\n");

close(fd);

return 0;
}

You might also like