Operating Systems - Lab Manuals
Operating Systems - Lab Manuals
Operating Systems
Lab Manuals
Table of Contents
Sr.
Description Page
No
1 List of Equipment 3
|Page2
lOMoAR cPSD| 17676710
List of Equipment
1 Workstations (PCs)
|Page3
lOMoAR cPSD| 17676710
EXPERIMENT 1
Introduction to OS and LINUX
OBJECTIVE:
To get familiarized with the basics of operating systems
Learn the basic commands used in Linux
BACKGROUND:
On Computer Startup:
Operating System:
What is an Operating System?
Supports computer’s basic functions as shown in Figure 1.1
What tasks does an OS Perform?
Processor management
Memory management
Device management
Storage management
Application interface
User interface
Types
Linux
Windows 8, Windows 7, Vista, XP
Mac
OS Basic Functions
Figure 1.1
|Page4
lOMoAR cPSD| 17676710
What is LINUX?
A fully networked 32/64-bit Unix-like Operating System
Compilers Like C, C++
Multi-user, Multitasking
Coexists with other Operating Systems
Includes the Source Code
Open Source
Why is it Significant?
Growing popularity
Powerful
Runs on multiple hardware platforms
Users like its speed and stability
No requirement for the latest hardware
It is free
Licensed under GPL (General Public License)
System Structure:
An operating system is a construct that allows the user application programs to interact with
the system hardware. This is further divided in two layers i.e Kernel and Shell. Kernel deals
with the Hardware and Shell deals with Applications as shown in Figure 1.2.
Applications
Shell
Kernel
Hardware
|Page5
lOMoAR cPSD| 17676710
To execute a command, type its name and arguments at the command line
<command_name> <space> <options> <space> <arguments>
Editors:
Several Choices are available:
vi Standard UNIX editor
the XEDIT-like editor
xedit X Windows text editor
emacs Extensible, Customizable Self-Documenting Display Editor
pico Simple display-oriented text editor
nedit X windows Motif text editor
|Page6
lOMoAR cPSD| 17676710
Windows LINUX
The directories in the MS-DOS path are Paths are separated by ‘/’.
separated by ‘\’ File names are case-sensitive.
File names are case insensitive. There is only a single hierarchal
Where DOS/Windows had various directory structure (which resembles
partitions and then directories under a tree).Everything starts from the
those partitions. root directory, represented by '/', and
An executable is one with an extension then
of .exe, .com or .bat. expands into sub-directories.
You can set attributes to make the file Any file whose execute permission is
read-only, hidden turned on is executable
You can set permissions on a file
|Page7
lOMoAR cPSD| 17676710
Virtual Machine:
|Page8
lOMoAR cPSD| 17676710
|Page9
lOMoAR cPSD| 17676710
| P a g e 10
lOMoAR cPSD| 17676710
EXPERIMENT 2
Creating, Compiling, and Executing C/C++ programs using gcc/g++
Compilers and Make File
OBJECTIVE:
Learn the use of g++ and gcc compilers to compile and execute C++ and C programs
To get familiarized with the working of Make File for C/C++ programs
BACKGROUND:
For C:
Command: gcc source_files… -o output_file
Source files need not be cpp or c files. They can be preprocessed files, assembly files, or
object files.
Every c/cpp file has its own preprocessed file, assembly file, and object file.
2. For running the compilation process till assembly file generation, we use the –S option.
3. For running the compilation process till object file creation, we use the –c option.
A file generated using any option can be used to create the final executable. For example,
let’s suppose that we have two source files: math.cpp and main.cpp, and we create object
files:
| P a g e 11
lOMoAR cPSD| 17676710
The object files created using the above two commands can be used to generate the final
executable.
The file named “my_executable” is the final exe file. There is t h e specific extension
for
executable files in Linux.
Command line arguments are a way to pass data to the program. Command line arguments
are passed to the main function. Suppose we want to pass two integer numbers to the main
function of an executable program called a.out. On the terminal write the following line:
./a.out 1 22
./a.out is the usual method of running an executable via the terminal. Here 1 and 22 are the
numbers that we have passed as a command-line argument to the program. These
arguments are passed to the main function. For the main function to be able to accept the
arguments, we have to change the signature of the main function as follows:
argc is the counter. It tells how many arguments have been passed.
argc, i n t hi s case, will not be equal to 2, but it will be equal to 3. This is because the name
./a.out is also passed as a command line argument. At index 0 of arg, we have ./a.out; at
index 1, we have 1; and at index 2, we have 22. Here 1 and 22 are in the form of character
strings, we have to convert them to integers by using a function atoi. Suppose we want to add
the passed numbers and print the sum on the screen:
Compiler Process:
Compiler Stage: All C++ language code in the .cpp file is converted into a lower-level
language called Assembly language; making .s files.
Assembler Stage: The assembly language code made by the previous stage is then
converted into object code which are fragments of code that the computer
understands directly. An object code file ends with .o.
| P a g e 12
lOMoAR cPSD| 17676710
Linker Stage: The final stage in compiling a program involves linking the object code
to code libraries that contain certain "built-in" functions, such as cout. This stage
produces an executable program, which is named a.out by default.
Makefiles:
Using makefiles:
Naming:
Running make:
make
Sample makefile:
target : dependencies
Example:
my_prog: eval.o main.o
g++ -c main.c
| P a g e 13
lOMoAR cPSD| 17676710
Variables:
Figure 3.1
Automatic variables:
Automatic variables are used to refer to specific parts of rule
components.eval.o: eval.c eval.h
g++ -c eval.c
| P a g e 14
lOMoAR cPSD| 17676710
Conditionals (directives):
Possible conditionals are:
if ifeq ifneq ifdef ifndef
All of them should be closed with endif.
Complex conditionals may use elif and else.
Example:
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc) #no tabs at the beginning
else
libs=$(normal_libs) #no tabs at the beginning
endif
In-Lab Questions:
Question 1: Write a C or C++ program that accepts a file name as a command line argument
and prints the file’s contents on the console. If the file does not exist, print some error on the
screen.
Question 2: Write a C or C++ program that accepts a list of integers as command line
arguments sorts the integers and prints the sorted integers on the screen.
Question 3: Create the following classes in separate files (using .h and .cpp files)
Student, Teacher, Course.
A student has a list of courses that he is enrolled in.
A teacher has a list of courses that he is teaching.
A course has a list of students who are studying it and a list of teachers who are teaching
thecourse. Create some objects of all classes in the main function and populate them with
data.
Now compile all classes using makefile
| P a g e 15
lOMoAR cPSD| 17676710
Post-Lab Questions:
Problem 1: Write a C/C++ program that takes some integers as command line parameters,
stores them in an array, and prints the sum and average of that array. Also, note that you have
torun the program for all possible error checks.
Problem 2: Write a C/C++ program that takes some integers in the form of series as
command line parameters; stores them in an array then computes the missing element from
that series and outputs that missing element to the file.
Problem 3: Write a C/C++ program that reads the file in which there are integers related to a
series and stores them in an array then computes the missing element from that series and
outputs that missing element to file.
Problem 4: Create the following classes in separate files (using .h and .cpp files)
LetterCount, WordCount, LineCount. LetterCount counts the number of letters in a text file.
WordCount counts the number of words in a text file. LineCount counts the number of lines
in a text file. Create some objects of all classes in the main function and populate them with
data. Now compile all classes using makefile
| P a g e 16
lOMoAR cPSD| 17676710
EXPERIMENT 3
System Calls
OBJECTIVE:
To understand about Linux system calls and their use in processes
BACKGROUND:
System calls provide the means for a user program to ask the operating system to perform
tasks reserved for the operating system on the user program’s behalf. A system call is
invoked in a variety of ways, depending on the functionality provided by the underlying
processor. In all forms, it is the method used by a process to request action by the operating
system. Figure 4.1 shows some of the primarily used system calls.
I. fork()
Has a return value
Parent process => invokes fork() system call
| P a g e 17
lOMoAR cPSD| 17676710
II. wait ()
Used by the parent process
The parent’s execution is suspended
The child remains its execution
On termination of the child, returns an exit status to the OS
Exit status is then returned to the waiting parent process //retrieved by wait ()
Parent process resumes execution
#include <sys/wait.h>
#include <sys/types.h>
III. exit()
The process terminates its execution by calling the exit() system call
It returns exit status, which is retrieved by the parent process using the wait() command
EXIT_SUCCESS // integer value = 0
EXIT_FAILURE // integer value = 1
OS reclaims resources allocated by the terminated process (dead process) Typically
performs clean-up operations within the process space before returning control to the
OS
Terminates the current process without any extra program clean-up
Usually used by the child process to prevent from erroneous release of resources
belonging to the parent process
elpmaxE:
#include <stdio.h>
#include <sys/types.h>
int main()
{
pid_t pid;
pid=fork();
if(pid==0){
printf(“I’m in a child process \n\n”);
}
else if (pid>0){
printf(“I’m in the parent process \n\n”);
}
else
{
printf(“Error \n\n”);
}
return 0;
} | P a g e 19
lOMoAR cPSD| 17676710
In-lab problems:
1. Create a program that creates a child process. The child process prints “I am a
child process” 100 times in a loop. Whereas the parent process prints “I am a
parent process” 100 times in a loop.
2. Create a program named stat that takes an integer array as a command line
argument (delimited by some character such as $). The program then creates 3
child processes each of which does exactly one task from the following.
a) Adds them and prints the result on the screen. (done by child 1)
b) Shows the average on the screen. (done by child 2)
c) Prints the maximum number on the screen. (done by child 3)
Post-Lab Questions:
Q1. Write a program that uses a fork () system call to create a child process. The child
process prints the contents of the current directory and the parent process waits for the child
process to terminate.
Q2. Write a program that prints its PID and uses a fork () system call to create a child
process. After the fork () system call, both parent and child processes print what kind of
processthey are and their PID. Also, the parent process prints its child’s PID, and the child
process
prints its parent’s PID.
| P a g e 20
lOMoAR cPSD| 17676710
EXPERIMENT 4
Threads
OBJECTIVE:
To understand and learn about threads and their implementation in programs
BACKGROUND:
Threads:
pthread_create(pthread_t* , NULL, void*, void*)
The first Parameter is the pointer of the thread ID it should be different for all threads.
The second Parameter is used to change the stack size of the thread. Null means use the
default size.
The third perimeter is the address of function which we are going to use as thread.
Forth parameter is an argument to
function.pthread_join(i pthread_t , void**)
Pthread join is used in the main program to wait for the end of a particular thread.
The first parameter is the Thread ID of a particular thread.
The second Parameter is used to catch the return value from the thread.
Thread Library:
POSIX Pthreads
Two general strategies for creating multiple threads.
a) Asynchronous threading:
Parent and child threads run independently of each other
Typically little data sharing between threads
b) Synchronous threading:
Parent thread waits for all of its children to terminate
Children threads run concurrently
Significant data sharing
Pthreads:
pthread.h
Each thread has a set of attributes, including stack size and scheduling information
In a Pthreads program, separate threads begin execution in a specified function
//runner()
When a program begins
A single thread of control begins in the main()
main() creates a second thread that begins control in the runner() function
Both threads share the global data
| P a g e 21
lOMoAR cPSD| 17676710
Example:
Design a multi-threaded program that performs the summation of a non-negative integer in a
separate thread using the summation function:
𝑁
𝑠𝑢𝑚 = ∑ i
𝑖=0
For example, if N were 5, this function would represent the summation of integers from 0 to
5, which is 15.
#include <pthread.h>
#include <stdio.h>
int sum; //this data is shared by the thread(s)
//The thread will begin control in this
functionvoid* runner(void *parameters)
{
int i, upper=atoi(parameters);
if(upper>0)
{
for(i=1;i<=upper;i++)
sum=sum+i;
}
pthread_exit(0);
}//End runner
int main(int argc, char*argv[])
{
//thread identifier
pthread_t threadID;
//set attributes for the thread
pthread_attr_t attributes;
//get the default attributes
pthread_attr_init(&attributes);
//create the thread
pthread_create(&threadID, &attributes, runner,
argv[1]);
//now wait for the thread to exit
pthread_join(threadUD, NULL);
printf("sum=%d\n",sum);
}
Question 1:
Write a program that takes some positive integers (let’s say N number of positive integers) as
command line parameters, creates N synchronous threads, and sends the corresponding
integer as a parameter to the thread function Fibonaccigenerator. The function returns the
generated series to the main thread. The main thread will then print the thread number and the
series generated by that thread. The output will be like:
Thread 1: 0 1 1 2 3 5 8 13
| P a g e 22
lOMoAR cPSD| 17676710
Example:
If you pass as command line argument the following numbers: 3 13 34 89
Then the program will create 4 threads. The first thread will find Fibonacci terms until 3 is
generated, the second Fibonacci term will find Fibonacci terms until the term generated is 13
so on and so forth. All generated terms will be output on the screen by the main thread as
follows:
Thread 0: 0, 1, 1, 2, 3
Thread 1: 0, 1, 1, 2, 3, 5, 8, 13
Thread 2: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Thread 3: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
It is possible that the number passed to the thread is not a Fibonacci number. In this case,
thethread will generate numbers until the term generated is greater than the passed number.
Forexample, if 7 is passed as a parameter to a thread, then the thread will return the
following series:
0, 1, 1, 2, 3, 5, 8
Question 2:
Write a multithreaded program that calculates various statistical values for a list of numbers.
This program will pass a series of numbers on the command line and will then create three
separate worker threads. One thread will determine the average of the numbers, the second
will determine the maximum value, and the third will determine the minimum value.For
example, suppose your program has passed the integers. (The array of numbers must be
passed as a parameter to threads, and the thread must return the calculated value to the main
thread).
90 81 78 95 79 72 85
The main thread will print:
The average value is 82
The minimum value is 72
The maximum value is 95
| P a g e 23
lOMoAR cPSD| 17676710
EXPERIMENT 5
InterProcess Communication using Pipes
OBJECTIVE:
Learn and Understand InterProcess Communication using the implementation of Pipes
BACKGROUND:
Pipes:
Ordinary pipes allow two processes to communicate in standard producer-consumer fashion:
the producer writes to one end of the pipe (the write-end) and the consumer reads from the
other end (the read-end). As a result, ordinary pipes are unidirectional, allowing only one-
way communication. If two-way communication is required, two pipes must be used, with
each pipe sending data in a different direction.
A pipe has a read end and a write end.
Data written to the write end of a pipe can be read from the read end of
the pipe.
Creating an Ordinary Pipe:
On UNIX and LINUX systems, ordinary pipes are constructed using the function
int pipe(int fd[2]) – which creates a pipe
that returns two file descriptors, fd[0], fd[1].
Fd[0] is the read-end of the pipe.
Fd[1] is the write-end of the pipe.
Fd[0] is opened for reading
Fd[1] is open for writing. Pipe() sets 0 on success, -1 on failure, and sets errno
accordingly.
The standard programming model is that after the pipe has been set up, two (or more)
cooperative processes will be created using read() and write().
Pipes opened with pipe() should be closed with close(int fd).
Example 1:
int pdes[2];
pipe(pdes);
if(fork()==0)
{//child
close(pdes[1]);
read(pdes[0]); //read from parent
}
else
{
close(pdes[0]);
write(pdes[1]); //write to child
}
| P a g e 24
lOMoAR cPSD| 17676710
Example 2:
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
int pfd[2];
pid_t cpid;
char buf;
if (pipe(pfd)==-1)
{perror("pipe");
exit(EXIT_FAILURE);}
cpid=fork();
if (cpid==-1)
{perror("fork");
exit(EXIT_FAILURE);}
if (cpid==0)
{
close(pfd[1]);
while(read(pfd[0],&buf,1)>0)
{printf(buf);}
close(pfd[0]);
exit(EXIT_SUCCESS);
}
else
{close(pfd[0]);
write(pfd[1],argv[1],strlen(argv[1]));
close(pfd[1]);
wait(NULL);
exit(EXIT_SUCCESS);
}
}
| P a g e 25
lOMoAR cPSD| 17676710
In-lab Questions:
Q1. Design a program using ordinary pipes in which one process sends a string message to a
second process, and the second process reverses the case of each character in the message and
sends it back to the first process. For example, if the first process sends the message Hi
There, the second process will return hI tHERE. This will require using two pipes, one for
sending the original message from the first to the second process, and the other for sending
the modified message from the second back to the first process.
Q2. Design a file-copying program named FileCopy using ordinary pipes. This program will
pass two parameters: the first is the name of the file to be copied, and the second is the name
of the copied file. The program will then create an ordinary pipe and write the contents of the
file to be copied to the pipe. The child process will read this file from the pipe and write it to
the destination file. For example, if we invoke the program as follows: FileCopy input.txt
copy.txt the file input. txt will be written to the pipe. The child process will read the contents
of this file and write it to the destination file copy.txt.
| P a g e 26
lOMoAR cPSD| 17676710
EXPERIMENT 6
InterProcess Communication Using Shared
Memory
OBJECTIVE:
Learn and Understand InterProcess Communication using the implementation of
SharedMemory
BACKGROUND:
Shared Memory:
The problem with pipes, FIFO, and message queues – is that for two processes to
exchangeinformation. The information has to go through the kernel.
A total of four copies of data are required (2 read and 2 write). So, shared memory provides a
way to let two or more processes share a memory segment. With Shared Memory the data is
only copied twice – from the input file into shared memory and from shared memory to the
output file. Figures 7.1 and 7.2 are a pictorial representation of the above concept.
| P a g e 27
lOMoAR cPSD| 17676710
Return Values:
Upon successful completion, shmget() returns the positive integer identifier of a shared
memory segment. Otherwise, -1 is returned
| P a g e 28
lOMoAR cPSD| 17676710
Return Values:
Upon success, shmat() returns the address where the segment is attached; otherwise, -1 is
returned and errno is set to indicate the error.
This system call is used to detach a shared memory region from the process’s address space.
Return Values:
Upon success, shmdt() returns 0; otherwise, -1 is returned and errno is set to indicate the
error.
How to Delete Shared Memory Region:
IPC_RMID marks the segment to be destroyed. The segment will be destroyedonly after
the last process detaches it (The caller must be the owner or creator of the segment, or be
privileged). The buf argument is ignored.
Return Values:
For IPC_RMID operation, 0 is returned on success; else -1 is returned.
Shmctl(shmid, IPC_RMID, NULL);
| P a g e 29
lOMoAR cPSD| 17676710
In-Lab Questions:
1. Create a private shared memory in C/C++. The process then creates a child and waits
for the child to write the file’s contents to shared memory. The parent then reads the
shared memory, changes the case of each character, and removes all integers fromthe
data. The child reads it back and writes the changed data back to the same file. (The
file name is passed as a command line argument).
2. Create a C++/C program that creates a shared memory and waits for the other process
to write n data of n number of Students. The process that created the shared memory
then writes the data of students to the file.
| P a g e 30
lOMoAR cPSD| 17676710
EXPERIMENT 7
InterProcess Communication using Sockets
OBJECTIVE:
Learn and Understand InterProcess Communication using socket programming
BACKGROUND:
Sockets:
IP address
Identify hosts connected to the internet
Written in a dotted-decimal notation of the form N1.N2.N3.N4 where each Ni is a
decimal number between 0 and 255
Socket
To identify a particular process running on a host
An integer number
Port numbers smaller than 1024 i.e. 0-1023 are well-known ports // port 80 for
HTTP (standard service)
We can use port numbers from 1024 to 65535
Works like a telephone extension
Main phone number computer IP address
Extension numbers set of port numbers
Loopback IP:
| P a g e 31
lOMoAR cPSD| 17676710
Types of Socket:
listen( )
Waits for incoming connections
int status=listen(int sd, int backlog);
sd socket on which the server is listening
backlog maximum number of connections pending in a queue
status return -1 on error
accept( )
Blocking system call
Waits for an incoming request and when received, creates a socket for it
int sid=accept(int sd, struct sockaddr *cli_addr, int *addrlen)
sid socket file descriptor for communication
sd socket file descriptor used for listening
addr poitner to struct sockaddr containing client address IP and Port
addrlen size of struct sockaddr
send( )
int sb=send(int sd, const char *msg, int len, int flags);
sb return number of bytes send of -1 for error
sd socket file descriptor
msg is a pointer to data buffer
len number of bytes we want to send
flags set it to 0 for default
recv( )
int rb=recv(inst sd, char *buf, int len, int flags);
rb number of bytes received or -1 on error. 0 if connection is closed at other
side
sd socket file descriptor
buf is a pointer to data buffer
len receive up to len bytes in buffer pointer
flag set it to 0 for default
| P a g e 33
lOMoAR cPSD| 17676710
close( )
Close connection on the given socket and frees the socket descriptor
int close(int sd);
struct sockaddr:
Generic
Holds socket address information for many types of sockets
struct_sockaddr{
unsigned short sa_family; //address family AF_xxx
unsigned short sa_data[14]; //14 bytes of protocol addr
struct sockaddr_in:
IPV4 specific
struct_sockaddr_in{
short int sin_family; //set to AF_INET
unsigned short int sin_port; //port number
struct in_addr sin_addr; //internet address
unsigned char sin_zero[8]; //set to all zeros
}
Client-Server Model:
Client-Server mechanism has been shown in a generic model in Figure 8.1 and Figure 8.2
shows the model for the implementation here in specific regard to IPC.
| P a g e 34
lOMoAR cPSD| 17676710
ipconfig // windows
ifconfig // linux
hostname –I //linux
ip addr show //linux
Network tools
Header Files:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
| P a g e 35
lOMoAR cPSD| 17676710
Server:
int main(){
int sd;
char* msg="connected";
struct sockaddr_in my_addr, client_addr;
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(4999);
my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
sd=socket(AF_INET,SOCK_STREAM,0);
bind(sd,(struct sockaddr *) &my_addr,sizeof(struct
sockaddr_in));
listen(sd,5);
int i=0;
while(i<1)
{
int size=sizeof(struct sockaddr);
int new_sd=accept(sd,(struct sockaddr*)&client_addr,
&size);
send(new_sd, msg,100,0);
++i;
}
return 0;
}
Client:
int main()
{
int sd;
char msg[100];
struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(4999);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
sd=socket(AF_INET,SOCK_STREAM,0);
connect(sd,(struct sockaddr*)
&server_addr,sizeof(struct sockaddr));
recv(sd,msg,100,0);
printf("%s\n",msg);
return 0;
}
| P a g e 36
lOMoAR cPSD| 17676710
EXPERIMENT 8
Named Pipes
OBJECTIVE:
Learn and execute InterProcess Communication using the implementation of named pipes
BACKGROUND:
Named Pipes:
Input/output Redirection:
Dup2:
Dup2 system call is used to make alias of a file descriptor, for example:
The above system call will first close file descriptor 1 using a close system call. Then, file
descriptor fd’s data will be copied to file descriptor 1. So, every write that is made using fd=1
will then be written to file.txt
Similarly,
| P a g e 37
lOMoAR cPSD| 17676710
On the shell, we make the input of one command as the output of another
command byusing the | symbol.
ls | sort
ls displays directory contents and sort simply sorts the input data. In the above command, we
arepassing the output of the ls command as input to the sort command. The output shown on
the screen will be generated by the sort command. Behind the scenes, it is done by named
pipes and dup2.
To redirect the output of a command to a file, we can use > symbol, such as
Ls > 1.txt
The above command will redirect the output generated by the ls command to file 1.txt
In-lab Questions
Question 1:
Create 2 independent programs that perform communication using named pipes. One
program will be the server program that will wait for the client to send some data via a
namedpipe. The data sent by the client is as follows:
The operands can be +, -, *, /. The server will then apply the operator on the operands and
return the result to the client via a named pipe. The client will then print the result on the
screen
For example, if the client passes the following to the server: + 4 10, then the server will
calculate 4+10 and return 14 to the client via the pipe. The client will then print it.
Question 2:
Implement a program that executes the command:
ls | sort
This will help: execlp("sort","sort",NULL);
| P a g e 38
lOMoAR cPSD| 17676710
EXPERIMENT 9
Semaphores using Shared Memory
OBJECTIVE:
Learn the concept of semaphores
Understand the use of Shared Memory
Learn to use semaphores for synchronization in InterProcess Communication
BACKGROUND:
Race Condition:
A situation in which several tasks access and manipulate the same data concurrently and
the outcome of the execution depends on the particular order in which the access takes
place.
Example:
Suppose that the value of the variable counter = 5.
Process 1 and process 2 execute the statements “counter++” and “counter--”
concurrently.
Following the execution of these two statements, the value of the variable counter
maybe 4, 5, or 6! Table 10.1 shows what happens in this case …
register1=counter register2=counter
register1=register1 + 1 register2=register2 - 1
counter=register1 counter=register2
There are two essential needs for synchronization between multiple processes
executing on shared memory
| P a g e 39
lOMoAR cPSD| 17676710
Binary semaphore:
Counting Semaphore:
Critical Sections:
Unix Semaphores:
| P a g e 41
lOMoAR cPSD| 17676710
#include <semaphore.h>
POSIX semaphores come in two forms: named semaphores and unnamed
semaphores.
System Calls:
Recall that shared memory segments must be removed before the program exits
“An unnamed semaphore should be destroyed with sem_destroy() before the memory
in which it is located is deallocated.”
“Failure to do this can result in resource leaks on some implementations.”
#include <semaphore.h>
sem_init() initializes the unnamed semaphore at the address pointed to by sem. The
value argument specifies the initial value for the semaphore.
If pshared has the value 0, then the semaphore is shared between the threads of a
process.
If pshared is nonzero, then the semaphore is shared between processes, and should be
located in a region of shared memory.
| P a g e 42
lOMoAR cPSD| 17676710
If the semaphore currently has the value zero, then the call blocks until either it
becomes possible to perform the decrement (i.e., the semaphore value rises above
zero), or a signal handler interrupts the call.
Destroys the unnamed semaphore at the address pointed to by sem. Only a semaphore
that has been initialized by sem_init(3) should be destroyed using sem_destroy().
Destroying a semaphore that other processes or threads are currently blocked on (in
sem_wait(3) produces undefined behavior.
Using a semaphore that has been destroyed produces undefined results until the
semaphore has been reinitialized using sem_init(3).
Examples:
Example1
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mutex;
| P a g e 43
lOMoAR cPSD| 17676710
pthread_create(&t2,NULL,thread,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
sem_destroy(&mutex);
return 0;
}
Example2
#include <sys/wait.h>
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
int main(int argc, char **argv)
{
int i, nloop=10, *ptr;
sem_t mutex;
int shmid2,shmid1;
int SHMSIZE=1024;
sem_t *p_mutex;
if((shmid2 = shmget(IPC_PRIVATE,SHMSIZE,0666))<0)
{
perror("shmget");
exit(1);
}
p_mutex = (sem_t*) shmat(shmid2,NULL,0);
if(p_mutex==(sem_t *)-1)
{
perror("mutex shmat fails");
exit(0);
}
if(p_mutex == (sem_t*)-1)
{
perror("semaphore initialization");
exit(0);
}
if (fork()==0)
{
sem_wait(p_mutex);
for (i=0;i<nloop;i++)
printf("child: %d\n",(*ptr)++);
sem_destroy(p_mutex);
shmctl(shmid2,IPC_RMID,(struct shmid_ds*)0);
shmctl(shmid1,IPC_RMID,(struct shmid_ds*)0);
exit(0)};
| P a g e 44
lOMoAR cPSD| 17676710
sem_post(p_mutex);
for (i=0;i<nloop;i++)
printf("parent: %d\n",(*ptr)++);
exit(0);
return 0;
}
| P a g e 45
lOMoAR cPSD| 17676710
EXPERIMENT 10
Memory Mapped Files
OBJECTIVE:
Learn the concept of Memory Mapped Files
BACKGROUND:
Memory mapping a file is accomplished by mapping a disk block to a page (or pages) in
memory. Subsequent reads and writes to the file are handled as routine memory accesses.
Manipulating files through memory rather than incurring the overhead of using the read()
and write() system calls simplifies and speeds up file access and usage. Figure 11.1 shows
memory mapping for two processes A and B.
void *mmap(void *addr, size_t len, int prot, int flags, int fields, off_t off);
addr: This is the address we want the file mapped into. The best way to use
this is to set it to (caddr_t)0 or NULL and let the OS choose it for you. If
you tell it to use an address the OS doesn't like (for instance, if it's not a
multiple of the virtual memory page size), it'll give you an error.
len: This parameter is the length of the data we want to map into memory. This
can be any length you want. (Aside: if len is not a multiple of the virtual
memorypage size, you will get a block size that is rounded up to that size. The
extra
bytes will be 0, and any changes you make to them will not modify the file.)
| P a g e 46
lOMoAR cPSD| 17676710
Return value:
• mmap() returns a pointer to the mapped area. On error, the value MAP_FAILED
is returned.
Munmap:
• int munmap(void *addr, size_t len);
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
int main(int argc, char*argv[]){
int fd;
char* data;
if((fd = open("m.c",O_RDONLY)) == -1)
{
perror("open");
exit(1);
}
data = mmap(NULL, getpagesize(), PROT_READ,MAP_SHARED, fd,0);
printf("File contains: %s\n", data);
return 0;}
| P a g e 47
lOMoAR cPSD| 17676710
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <time.h>
int main(int argc, char*argv[])
{
int fd;
void* file_memory;
fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
/*creates the memory mapping */
file_memory = mmap(NULL,256,PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
printf("%s", (char*) file_memory);
/*release the memory*/
munmap(file_memory,256);
return 0;
}
In-Lab Question:
Write C/C++ code for a program that takes as command line argument the file name and the
substring to be found in the file. Your program will make a memory map of the file and find
the number of times the substring has occurred in the file. Create 2 threads for searching. The
first thread will search for a substring in the first half, and the second thread will search for
the string inthe second half of the map. Whenever a thread finds the string it increments the
count of some shared variable “count”. Since the count is being shared by both threads, you
must synchronize the access using semaphore. After both threads have terminated, the main
thread will print thecount on the screen.
Example:
If the data in the file is “We went shopping on Sunday. There was hustle and bustle in the
market. We also went shopping on Saturday.”, and the substring is “went shopping”; then
your program must output 2.
| P a g e 48
lOMoAR cPSD| 17676710
EXPERIMENT 11
File Allocation Strategies
OBJECTIVE:
Learn to simulate the following file allocation strategies
a) Sequential
b) Linked
c) Indexed
BACKGROUND:
A file is a collection of data, usually stored on disk. As a logical entity, a file enables to
division of data into meaningful groups. As a physical entity, a file should be considered in
termsof its organization. The term “file organization” refers to how data is stored in afile
and, consequently, the method(s) by which it can be accessed.
In this file organization, the records of the file are stored one after another both physically
and logically. That is, the record with sequence number 16 is located just after the 15th
record. A record of a sequential file can only be accessed by reading all previous records.
With linked allocation, each file is a linked list of disk blocks; the disk blocks may be
scattered anywhere on the disk. The directory contains a pointer to the first and the last
blocks of the file. Each block contains a pointer to the next block.
The indexed file allocation strategy brings all the pointers together into one location: an
index block. Each file has its own index block, which is an array of disk-block addresses.
The ith entry in the index block points to the ith block of the file. The directory contains the
addressof the index block. To find and read the ith block, the pointer in the ith index-block
entry is used.
Example:
Taking an example of Sequential file allocation we see through its simulation how records of
file are to be stored one after the other. Each record in spread over different blocks which are
all there in a sequence.
| P a g e 49
lOMoAR cPSD| 17676710
#include<stdio.h>
struct fileTable
{
char name[20];
int sb, nob;
}ft[30];
void main()
{
int i, j, n;
char s[20];
printf("Enter no of files :");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("\nEnter file name %d :",i+1);
scanf("%s",ft[i].name);
printf("Enter starting block of file %d :",i+1);
scanf("%d",&ft[i].sb);
printf("Enter no of blocks in file %d :",i+1);
scanf("%d",&ft[i].nob);
}
printf("\nEnter the file name to be searched -- ");
scanf("%s",s);
for(i=0;i<n;i++)
if(strcmp(s, ft[i].name)==0)
break;
if(i==n)
printf("\nFile Not Found");
else
{
printf("\nFILE NAME START BLOCK NO OF BLOCKS BLOCKS
OCCUPIED\n");
printf("\n%s\t\t%d\t\t%d\t",ft[i].name,ft[i].sb,ft[i].nob);
for(j=0;j<ft[i].nob;j++)
printf("%d, ",ft[i].sb+j);
}
}
Output:
| P a g e 50
lOMoAR cPSD| 17676710
In-lab Questions
Question 1:
Write a program to implement simulation for Linked File Allocation. You can use given
struct where the output of this simulation will be as given below:
struct fileTable
{ char name[20];
int nob;
struct block *sb;
}ft[30];
struct block
{ int bno;
struct block *next;
};
Output:
Question 2:
Write a program to implement simulation for Indexed File Allocation. Where structure
and output of this simulation will be as given below:
struct fileTable
{ char name[20];
int nob, blocks[30];
}ft[30];
Output:
| P a g e 51
lOMoAR cPSD| 17676710
EXPERIMENT 12
File Organization Techniques
OBJECTIVE:
Learn to simulate the following file organization techniques
a) Single level directory
b) Two level directory
c) Hierarchical
BACKGROUND:
The directory structure is the organization of files into a hierarchy of folders. In a single-level
directory system, all the files are placed in one directory. There is a root directory that has all
files. It has a simple architecture and there are no sub-directories. The advantage of a single
level directory system is that it is easy to find a file in the directory. In the two-level directory
system, each user has own user file directory (UFD). The system maintains a master block
that has one entry for each user. This master block contains the addresses of the directory of
the users. When a user job starts or a user logs in, the system's master file directory (MFD) is
searched. When a user refers to a particular file, only his own UFD is searched. This
effectively solves the name collision problem and isolates users from one another.
Hierarchical directory structure allows users to create their own subdirectories and to
organize their files accordingly. A tree is the most common directory structure. The tree has a
root directory, and every file in the system has a unique path name. A directory (or
subdirectory) contains a set of files or subdirectories.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct
{
char dname[10],fname[10][10];
int fcnt;
}dir;
void main()
{ int i,ch;
char f[30];
dir.fcnt = 0;
printf("\nEnter name of directory -- ");
scanf("%s", dir.dname);
| P a g e 52
lOMoAR cPSD| 17676710
while(1)
{
printf("\n\n1. Create File\t2. Delete File\t3. Search File \n 4. Display Files\t5. Exit\nEnter your
choice -- ");
scanf("%d",&ch);
switch(ch)
{
case 1: printf("\nEnter the name of the file -- ");
scanf("%s",dir.fname[dir.fcnt]);
dir.fcnt++;
break;
case 2: printf("\nEnter the name of the file -- ");
scanf("%s",f);
for(i=0;i<dir.fcnt;i++)
{
if(strcmp(f, dir.fname[i])==0)
{
printf("File %s is deleted ",f);
strcpy(dir.fname[i],dir.fname[dir.fcnt-1]);
break;
}
}
if(i==dir.fcnt)
printf("File %s not found",f);
else
dir.fcnt--;
break;
case 3: printf("\nEnter the name of the file -- ");
scanf("%s",f);
for(i=0;i<dir.fcnt;i++)
{
if(strcmp(f, dir.fname[i])==0)
{
printf("File %s is found ", f);
break;
}
}
if(i==dir.fcnt)
printf("File %s not found",f);
break;
case 4: if(dir.fcnt==0)
printf("\nDirectory Empty");
else
{
printf("\nThe Files are -- ");
for(i=0;i<dir.fcnt;i++)
printf("\t%s",dir.fname[i]);
}
break;
default: exit(0); } } }
| P a g e 53
lOMoAR cPSD| 17676710
In-lab Questions
Question 1:
Question 2:
Hint: Pointer variables of a struct may be used as there will be a tree-like structure.
| P a g e 54
lOMoAR cPSD| 17676710
EXPERIMENT 13
The Readers and Writers Problem (Part A)
Problem Statement:
Synchronization has always been a problem, you can find multiple solutions to
synchronization problems. You can observe a lot of systems around us where multiple
processes try to access the same database at the same time. Take the airline reservation
system orhotel reservation system for an example.
Your task is to develop a solution for The Readers and Writers Problem (A problem where
multiple Processes wish to read or write. It is acceptable to have multiple processes reading
the database at the same time, but if one process is updating (writing) the database, no other
processes may have access to the database, not even readers.).
| P a g e 55
lOMoAR cPSD| 17676710
EXPERIMENT 14
The Readers and Writers Problem (Part B)
Problem Statement:
Start with the solution developed for Experiment 13, and write a program to implement
that solution by creating a dummy database. After implementation, your task is to reflect
yourthoughts on the merits/demerits of the solution and suggest steps for improvement
where required.
| P a g e 56
lOMoAR cPSD| 17676710
Notice:
Copying and plagiarism of lab reports is a serious academic misconduct. First instance of
copying may entail ZERO in that experiment. Second instance of copying may be reported to
DC. This may result in awarding FAIL in the lab course.
| P a g e 57
lOMoAR cPSD| 17676710
Remember that the voltage of the electricity and the available electrical
current in EE labs has enough power to cause death/injury by electrocution. It
is around 50V/10 mA that the “cannot let go” level is reached. “The key to
survival is to decrease our exposure to energized circuits.”
Each circuit must be protected by a fuse or circuit breaker that will blow or
“trip” when its safe carrying capacity is surpassed. If a fuse blows or circuit
breaker trips repeatedly while in normal use (not overloaded), check for shorts
and other faults in the line or devices. Do not resume use until the trouble is
fixed.
Dimmed lights, reduced output from heaters and poor monitor pictures are all
symptoms of an overloaded circuit. Keep the total load at any one time safely
below maximum capacity.
If wires are exposed, they may cause a shock to a person who comes into
contact with them. Cords should not be hung on nails, run over or wrapped
around objects, knotted or twisted. This may break the wire or insulation.
Short circuits are usually caused by bare wires touching due to breakdown of
insulation. Electrical tape or any other kind of tape is not adequate for
insulation!
Electrical cords should be examined visually before use for external defects
such as: Fraying (worn out) and exposed wiring, loose parts, deformed or
missing parts, damage to outer jacket or insulation, evidence of internal
| P a g e 58
lOMoAR cPSD| 17676710
damage such as pinched or crushed outer jacket. If any defects are found the
electric cords should be removed from service immediately.
Pull the plug not the cord. Pulling the cord could break a wire, causing a short
circuit.
Plug your heavy current consuming or any other large appliances into an outlet
that is not shared with other appliances. Do not tamper with fuses as this is a
potential fire hazard. Do not overload circuits as this may cause the wires to
heat and ignite insulation or other combustibles.
Ensure lamps are free from contact with flammable material. Always use
lights bulbs with the recommended wattage for your lamp and equipment.
Be aware of missing ground prong and outlet cover, pinched wires, damaged
casings on electrical outlets.
Follow all written and verbal instructions carefully. If you do not understand a
direction or part of a procedure, ASK YOUR LAB ENGINEER / LAB
ASSISTANT BEFORE PROCEEDING WITH THE ACTIVITY.
Never work alone in the laboratory. No student may work in EE Labs without
the presence of the Lab engineer / Lab assistant.
| P a g e 59
lOMoAR cPSD| 17676710
Be prepared for your work in the EE Labs. Read all procedures thoroughly
before entering the laboratory. Never fool around in the laboratory.
Horseplay, practical jokes, and pranks are dangerous and prohibited.
Observe good housekeeping practices. Work areas should be kept clean and
tidy at all times.
Dress properly during a laboratory activity. Long hair, dangling jewelry, and
loose or baggy clothing are a hazard in the laboratory. Long hair must be tied
back, and dangling jewelry and baggy clothing must be secured. Shoes must
completely cover the foot.
Know the locations and operating procedures of all safety equipment including
fire extinguisher. Know what to do if there is a fire during a lab period; “Turn
off equipment, if possible and exit EE lab immediately.”
| P a g e 60
lOMoAR cPSD| 17676710
3. Design: If applicable, draw the flow chart for the program. How do the new
constructs facilitate achievement of the Objective; if possible, a comparison in
terms of efficacy and computational tractability with the alternate constructs?
4. Issues: The bugs encountered and the way they were removed.
| P a g e 61