OPERATING SYSTEM ETCS-352 Faculty Name:- Student Name:Roll No:Semester:- 6th Sem Maharaja Agrasen Institute of Technology, PSP Area, Sector - 22, Rohini, New Delhi – 110085 INDEX Exp No 1. 2. 3. 4. 5. Experiment Name Introduction and installation of Linux Operating System Introduction of Basics Files, Directories, System Commands of Linux I. Write a script to find the greatest of three numbers (numbers passed as command line parameters) II. Write a script to check whether the given no. is even/odd. III. Write a script to check whether the given no. is prime or not. IV. Write a script to check whether the given input is a number or a string. Write a program to implement CPU scheduling for first come first serve. Write a program to implement CPU scheduling for shortest job first. 6. Write a program to perform priority scheduling 7. Write a program to implement CPU scheduling for Round Robin. 8. Write a program for page replacement policy using:a) LRU b) FIFO Date of Performance Date of Checking R1 (3) R2 (3) R3 (3) R4 (3) R5 (3) Total Marks (15) Signature c) Optimal 9. 10. 11. Write a program to implement first fit, best fit and worst fit algorithm for memory management. Write a program to implement reader/writer problem using semaphore. Write a program to implement Banker’s algorithm for deadlock avoidance Overall Comments: Signature: Faculty Name: Dr. Sandeep Tayal EXPERIMENT 1 Aim: Introduction and installation of Linux Operating System Introduction: Linux is a family of free and open-source operating systems based on the Linux kernel. Operating systems based on Linux are known as Linux distributions or distros. Examples include Debian, Ubuntu, Fedora, CentOS, Gentoo, Arch Linux, and many others. The Linux kernel has been under active development since 1991, and has proven to be extremely versatile and adaptable. You can find computers that run Linux in a wide variety of contexts all over the world, from web servers to cell phones. Today, 90% of all cloud infrastructure and 74% of the world’s smartphones are powered by Linux. However, newcomers to Linux may find it somewhat difficult to approach, as Linux filesystems have a different structure than those found on Windows or MacOS. Additionally, Linux-based operating systems depend heavily on working with the command line interface, while most personal computers rely on graphical interfaces. We need access to a computer running a Linux-based operating system. This can either be a virtual private server which you’ve connected to with SSH or your local machine. Note that this tutorial was validated using a Linux server running Ubuntu 20.04, but the examples given should work on a computer running any version of any Linux distribution. Linux Distributions: Linux distribution is an operating system that is made up of a collection of software based on Linux kernel or you can say distribution contains the Linux kernel and supporting libraries and software. And you can get Linux based operating system by downloading one of the Linux distributions and these distributions are available for different types of devices like embedded devices, personal computers, etc. Around 600 + Linux Distributions are available and some of the popular Linux distributions are: MX Linux Manjaro Linux Mint elementary Ubuntu Debian Solus Fedora Installation of Ubuntu 20.04 System Requirements: Ubuntu 20.04 Server Edition provides a common, minimalist base for a variety of server applications, such as file/print services, web hosting, email hosting, etc. This version supports four 64-bit architectures: amd64 (Intel/AMD 64-bit) arm64 (64-bit ARM) ppc64el (POWER8 and POWER9) s390x (IBM Z and LinuxONE) Download Installation Media: Step 1. Download the Installation Media, In a web browser, visit the Ubuntu download page and pick the Ubuntu version suitable for your machine. The most popular versions include: Ubuntu Desktop Ubuntu Server Ubuntu Derivatives Step 2. Once we find the version you need, click the green Download button. You’ll be taken to a thankyou page, and your download should start. (We will download and install Ubuntu 20.04 for desktops.) The download is an .iso file. We can use it to create a bootable USB drive. Step 3. Save the file to a location of your choice. Create Bootable USB Use Balena Etcher to burn the .iso file to the USB drive. 1. Open a search dialog, and type create startup. 2. If it’s not installed, the Software Center will offer the option to install it – choose the option for USB drive, then open the utility. 3. In the top pane, click Other, then browse and select the Ubuntu 20.04 .iso file you downloaded. 4. In the bottom pane, select your USB drive. 5. Click Make startup disk. Boot up Ubuntu from USB 1. Turn off your system. Make sure you remove all other USB devices, such as printers, memory cards, etc. 2. Insert the Ubuntu USB drive into the system and turn on your machine. There are two possible scenarios: a. The computer boots the USB drive automatically. b. You need to manually configure USB booting in the Boot Menu or BIOS/UEFI. 3. To manually configure the boot order, tap the boot menu key about once or twice per second as soon as the computer powers on. Install Ubuntu Using the guided installer 1. Click install Ubuntu 2. Select Language and Keyboard Layout. a. Normal Installation – This is the full Ubuntu Desktop experience, with office software, games, and media players. b. Minimal Installation – Choose this to save disk space, especially if you won’t be using media players or productivity software. 3. Select disk partition for installation 4. Select timezone 5. Create user account and password 6. Click continue and wait till the installation completes successfully. 7. Restart the PC and start using Ubuntu 20.04 Viva Questions: Q1: What is an operating system? What are the functions of the operating system? Ans: An Operating System (OS) is an interface between a computer user and computer hardware. An operating system is a software which performs all the basic tasks like file management, memory management, process management, handling input and output, and controlling peripheral devices such as disk drives and printers. Q2: What is Linux? Ans: Linux is an open-source operating system like other operating systems such as Microsoft Windows, Apple Mac OS, iOS, Google android, etc. Operating systems based on Linux are known as Linux distributions or distros. Q3: Name some popular Linux Distrubutions. Ans: MX Linux Manjaro Linux Mint Ubuntu Debian Solus Fedora EXPERIMENT 2 Aim: Introduction of basic files, directories, system commands of Linux. Linux Files A Linux file system is a structured collection of files on a disk drive or a partition. A partition is a segment of memory and contains some specific data. In our machine, there can be various partitions of the memory. Generally, every partition contains a file system. The general-purpose computer system needs to store data systematically so that we can easily access the files in less time. It stores the data on hard disks (HDD) or some equivalent storage type. There may be below reasons for maintaining the file system: Primarily the computer saves data to the RAM storage; it may lose the data if it gets turned off. However, there is non-volatile RAM (Flash RAM and SSD) that is available to maintain the data after the power interruption. Data storage is preferred on hard drives as compared to standard RAM as RAM costs more than disk space. The hard disk costs are dropping gradually compared to the RAM. The Linux file system contains the following sections: The root directory (/) A specific data storage format (EXT3, EXT4, BTRFS, XFS and so on) A partition or logical volume having a particular file system. Linux file system is generally a built-in layer of a Linux operating system used to handle the data management of the storage. It helps to arrange the file on the disk storage. It manages the file name, file size, creation date, and much more information about a file. If we have an unsupported file format in our file system, we can download software to deal with it. Linux file system has a hierarchal file structure as it contains a root directory and its subdirectories. All other directories can be accessed from the root directory. A partition usually has only one file system, but it may have more than one file system. A file system is designed in a way so that it can manage and provide space for non-volatile storage data. All file systems required a namespace that is a naming and organizational methodology. The namespace defines the naming process, length of the file name, or a subset of characters that can be used for the file name. It also defines the logical structure of files on a memory segment, such as the use of directories for organizing the specific files. Once a namespace is described, a Metadata description must be defined for that particular file. The data structure needs to support a hierarchical directory structure; this structure is used to describe the available and used disk space for a particular block. It also has the other details about the files such as file size, date & time of creation, update, and last modified. Also, it stores advanced information about the section of the disk, such as partitions and volumes. The advanced data and the structures that it represents contain the information about the file system stored on the drive; it is distinct and independent of the file system metadata. Linux Directories 1. General Files – It is also called ordinary files. It may be an image, video, program, or simple text files. These types of files can be in ASCII or Binary format. It is the most commonly used file in the Linux system. 2. Directory Files – These types of files are a warehouse for other file types. It may be a directory file within a directory (subdirectory). 3. Device Files – In a Windows-like operating system, devices like CD-ROM, and hard drives are represented as drive letters like F: G: H whereas in the Linux system device are represented as files. As for example, /dev/sda1, /dev/sda2 and so on. These are the common top-level directories associated with the root directory: /bin – binary or executable programs. /etc – system configuration files. /home – home directory. It is the default current directory. /opt – optional or third-party software. /tmp – temporary space, typically cleared on reboot. /usr – User related programs. /var – log files. Some other directories in the Linux system: /boot- It contains all the boot-related information files and folders such as conf, grub, etc. /dev – It is the location of the device files such as dev/sda1, dev/sda2, etc. /lib – It contains kernel modules and a shared library. /lost+found – It is used to find recovered bits of corrupted files. /media – It contains subdirectories where removal media devices inserted. /mnt – It contains temporary mount directories for mounting the file system. /proc – It is a virtual and pseudo-file system to contains info about the running processes with a specific process ID or PID. /run – It stores volatile runtime data. /sbin – binary executable programs for an administrator. /srv – It contains server-specific and server-related files. /sys – It is a virtual filesystem for modern Linux distributions to store and allows modification of the devices connected to the system. System Commands of Linux 1. curl: curl transfers a URL. Use this command to test an application's endpoint or connectivity to an upstream service endpoint. curl can be useful for determining if your application can reach another service, such as a database, or checking if your service is healthy. 2. python -m json.tool / jq: After you issue curl, the output of the API call may be difficult to read. Sometimes, you want to pretty-print the JSON output to find a specific entry. Python has a built-in JSON library that can help with this. You use python -m json.tool to indent and organize the JSON. To use Python's JSON module, pipe the output of a JSON file into the python -m json.tool command. 3. ls: ls lists files in a directory. Sysadmins and developers issue this command quite often. In the container space, this command can help determine your container image's directory and files. Besides looking up your files, ls can help you examine your permissions. In the example below, you can't run myapp because of a permissions issue. When you check the permissions using ls -l, you realize that the permissions do not have an "x" in -rw-r--r--, which are read and write only. 4. tail: tail displays the last part of a file. You usually don't need every log line to troubleshoot. Instead, you want to check what your logs say about the most recent request to your application. For example, you can use tail to check what happens in the logs when you make a request to your Apache HTTP server. 5. cat: cat concatenates and prints files. You might issue cat to check the contents of your dependencies file or to confirm the version of the application that you have already built locally. 6. grep: grep searches file patterns. If you are looking for a specific pattern in the output of another command, grep highlights the relevant lines. 7. ps: The ps command, part of the procps-ng package which provides useful commands for investigating process IDs, shows the status of a running process. 8. env: env allows you to set or print the environment variables. 9. top: top displays and updates sorted process information. Use this monitoring tool to determine which processes are running and how much memory and CPU they consume. 10. netstat: netstat shows the network status. This command shows network ports in use and their incoming connections. Viva Questions: Q1: What are some of the options available in UNIX command ps? Ans: Option Description -d Displays all processes with the exception of session leaders. -e Displays all processes. -f Displays a full listing. -glist Displays data for the list of group leader IDs. Q2: What are different sections of Linux File System? Ans: The Linux file system contains the following sections: The root directory (/) A specific data storage format (EXT3, EXT4, BTRFS, XFS and so on) A partition or logical volume having a particular file system. Q3: Name some directories in Linux System. Ans: /bin – binary or executable programs. /etc – system configuration files. /home – home directory. It is the default current directory. /opt – optional or third-party software. /tmp – temporary space, typically cleared on reboot. /usr – User related programs. /var – log files. /boot- It contains all the boot-related information files and folders such as conf, grub, etc. /dev – It is the location of the device files such as dev/sda1, dev/sda2, etc. /lib – It contains kernel modules and a shared library. /media – It contains subdirectories where removal media devices inserted. /run – It stores volatile runtime data. /sbin – binary executable programs for an administrator. /srv – It contains server-specific and server-related files. EXPERIMENT 3(i) Aim: Write a script to find greatest of three numbers (numbers passed as command line parameters) Code: max=$1 if [ $max -lt $2 ] then max=$2 fi if [ $max -lt $3 ] then max=$3 fi echo "Greatest of $1, $2, $3 is $max" Output: EXPERIMENT 3(ii) Aim: Write a script to check whether the given number is even/odd. Code: num=$1 if [ `expr $num % 2` -eq 0 ] then echo "$num is even" else echo "$num is odd" fi Output: EXPERIMENT 3(iii) Aim: Write a script to check whether the given number is prime or not. Code: echo "Enter the number" read num i=2 flag=0 while [ $i -lt `expr $num / 2` ] do if [ `expr $num % $i` == 0 ] then flag=1 fi i=`expr $i + 1` done if [ $flag -eq 0 ] then echo "$num is prime" else echo "$num is not prime" fi Output: EXPERIMENT 3(iv) Aim: Write a script to check whether the given input is a number or a string. Code: echo "Enter some value" read val if [[ $val =~ [0-9] ]] then echo "$val is a number" elif [[ $val == [a-zA-Z]* ]] then echo "$val is an string" fi Output: Viva Questions: Q1: What is Bash. Ans: Bash is a command line interpreter that typically runs in a text window where user can interpret commands to carry out various actions. Q2: How to run Bash script? Ans: sh filename.sh Q3: What is the command to take input in bash? Give example. Ans: Command used to take input is: read For ex: read val Q4: What is the command to print in bash? Give example. Ans: Command used to take input is: echo For ex: echo "$val is a number" EXPERIMENT 4 Aim: Write a program to implement CPU scheduling for first come first serve. Code: echo "Enter the number of tasks" read n for((i=0;i<$n;i++)) do echo "Enter the pid" read pid[$i] echo "Enter the arrival time" read arrival[$i] echo "Enter the burst time" read burst[$i] done #sort for((i=0;i<`expr $n-1`;i++)) do for((j=0;j<`expr $n-$i-1`;j++)) do if [ ${arrival[$j]} -gt ${arrival[$((j+1))]} ] then temp=${arrival[$j]} arrival[$j]=${arrival[$((j+1))]} arrival[$((j+1))]=$temp temp=${pid[$j]} pid[$j]=${pid[$((j+1))]} pid[$((j+1))]=$temp temp=${burst[$j]} burst[$j]=${burst[$((j+1))]} burst[$((j+1))]=$temp fi done done time=0 averageWaiting=0 averageTurnaround=0 for((i=0;i<$n;i++)) do if [ $time > ${arrival[$i]} ] then averageWaiting=`expr $averageWaiting + $time - ${arrival[$i]}` time=`expr $time + ${burst[$i]}` averageTurnaround=`expr $averageTurnaround + $time - ${arrival[$i]}` else time=`expr $time + ${arrival[$i]} + ${bust[$i]}` averageTurnaround=`expr $averageTurnaround + ${burst[$i]}` fi done averageWaiting=`expr $averageWaiting / $n` averageTurnaround=`expr $averageTurnaround / $n` echo "averageWaiting=$averageWaiting" echo "averageTurnaround=$averageTurnaround" Output: Viva Questions: Q1: What is Scheduling. Ans: The process scheduling is the activity of the process manager that handles the removal of the running process from the CPU and the selection of another process on the basis of a particular strategy. Q2: What is First Come First Serve Scheduling? Ans: First come first serve (FCFS) scheduling algorithm simply schedules the jobs according to their arrival time. The job which comes first in the ready queue will get the CPU first. The lesser the arrival time of the job, the sooner will the job get the CPU. Q3: What are advantages of FCFS? Ans: Advantages are: Simple Easy First come, First serve Q4: What are disadvantages of FCFS? Ans: Disadvantages are: 1. The scheduling method is non preemptive, the process will run to the completion. 2. Due to the non-preemptive nature of the algorithm, the problem of starvation may occur. 3. Although it is easy to implement, but it is poor in performance since the average waiting time is higher as compare to other scheduling algorithms. EXPERIMENT 5 Aim: Write a program to implement CPU scheduling for shortest job first. Code: echo "Enter number of jobs" read n sum=0 for((i=0;i<$n;i++)) do echo "Enter pid" read pid[$i] echo "Enter the arrival time" read arrival[$i] echo "Enter the burst time" read burst[$i] sum=`expr $sum + ${burst[$i]}` done for((i=0;i<`expr $n-1`;i++)) do for((j=0;j<`expr $n-$i-1`;j++)) do if [ ${arrival[$j]} -gt ${arrival[$((j+1))]} ] then temp=${arrival[$j]} arrival[$j]=${arrival[$((j+1))]} arrival[$((j+1))]=$temp temp=${pid[$j]} pid[$j]=${pid[$((j+1))]} pid[$((j+1))]=$temp temp=${burst[$j]} burst[$j]=${burst[$((j+1))]} burst[$((j+1))]=$temp fi done done time=${arrival[0]} averageWaiting=0 averageTurnaround=0 while(true) do min=-1 for((i=0;i<$n;i++)) do if [ ${arrival[$i]} -gt $time ] then break fi if [ "${pid[$i]}" = false ] then continue fi if [ $min -eq -1 ] then min=$i continue fi if [ ${burst[$i]} -lt ${burst[$min]} ] then min=$i fi done if [ $time -ge $sum ] then break fi if [ $min -eq -1 ] then time=`expr $time + 1` continue fi echo "Task pid=${pid[$min]}" echo "Time of running=$time" averageWaiting=`expr $averageWaiting + $time - ${arrival[$min]}` time=`expr $time + ${burst[$min]}` echo "Time of completion=$time" averageTurnaround=`expr $time - ${arrival[$min]} + $averageTurnaround` pid[$min]=false done averageWaiting=`expr $averageWaiting / $n` averageTurnaround=`expr $averageTurnaround / $n` echo "Average Waiting time=$averageWaiting" echo "Average Turn Around time=$averageTurnaround" Output: Viva Questions: Q1: Name different Scheduling Queues. Ans: The Operating System maintains the following important process scheduling queues − Job queue − This queue keeps all the processes in the system. Ready queue − This queue keeps a set of all processes residing in main memory, ready and waiting to execute. A new process is always put in this queue. Device queues − The processes which are blocked due to unavailability of an I/O device constitute this queue. Q2: What is Shortest Job First Scheduling? Ans: SJF scheduling algorithm, schedules the processes according to their burst time.In SJF scheduling, the process with the lowest burst time, among the list of available processes in the ready queue, is going to be scheduled next. Q3: What are advantages of SJF? Ans: Advantages are: 1. Maximum throughput 2. Minimum average waiting and turnaround time Q4: What are disadvantages of SJF? Ans: Disadvantages are: 1. May suffer with the problem of starvation 2. It is not implementable because the exact Burst time for a process can't be known in advance. EXPERIMENT 6 Aim: Write a program to implement priority scheduling. Code: echo "Priority Scheduling" echo "Enter number of tasks" read n for((i=0;i<$n;i++)) do echo "Enter PID" read pid[$i] echo "Enter Arrival Time" read arrival[$i] echo "Enter Burst Time" read burst[$i] echo "Enter Priority" read priority[$i] sum=`expr $sum + ${burst[$i]}` done #Sort for((i=0;i<`expr $n - 1`;i++)) do for((j=0;j<`expr $n - $i - 1`;j++)) do if [ ${arrival[$j]} -gt ${arrival[$((j+1))]} ] then temp=${arrival[$j]} arrival[$j]=${arrival[$((j+1))]} arrival[$((j+1))]=$temp temp=${pid[$j]} pid[$j]=${pid[$((j+1))]} pid[$((j+1))]=$temp temp=${burst[$j]} burst[$j]=${burst[$((j+1))]} burst[$((j+1))]=$temp temp=${priority[$j]} priority[$j]=${priority[$((j+1))]} priority[$((j+1))]=$temp fi done done time=${arrival[0]} averageWaiting=0 averageTurnaround=0 while(true) do min=-1 for((i=0;i<$n;i++)) do if [ ${arrival[$i]} -gt $time ] then break fi if [ "${pid[$i]}" = false ] then continue fi if [ $min -eq -1 ] then min=$i continue fi if [ ${priority[$i]} -gt ${priority[$min]} ] then min=$i fi done if [ $time -ge $sum ] then break fi if [ $min -eq -1 ] then time=`expr $time + 1` continue fi echo "Task pid=${pid[$min]}" echo "Time of running=$time" echo "Priority of task=${priority[$min]}" averageWaiting=`expr $averageWaiting + $time - ${arrival[$min]}` time=`expr $time + ${burst[$min]}` echo "Time of completion=$time" averageTurnaround=`expr $time - ${arrival[$min]} + $averageTurnaround` pid[$min]=false done averageWaiting=`expr $averageWaiting / $n` averageTurnaround=`expr $averageTurnaround / $n` echo "Average Waiting time=$averageWaiting" echo "Average Turn Around time=$averageTurnaround" Output: Viva Questions: Q1: What is Priority Scheduling? Ans: In Priority scheduling, there is a priority number assigned to each process. In some systems, the lower the number, the higher the priority. While, in the others, the higher the number, the higher will be the priority. The Process with the higher priority among the available processes is given the CPU. Q2: What are different types of Priority Scheduling? Ans: There are two types of priority scheduling algorithm exists. One is Preemptive priority scheduling while the other is Non Preemptive Priority scheduling. Q3: What are advantages of Priority Scheduling? Ans: Advantages are: Good way to ensure processes with higher priorities are handled first. Good when the resources are limited and priorities for each process are defined beforehand Q4: What are disadvantages of Priority Scheduling? Ans: Disadvantages are: Processes with lower priority may be starved Difficult to objectively decide which processes are given higher priority Low priority processes will be lost if the computer crashes EXPERIMENT 7 Aim: Write a program to implement CPU scheduling for Round Robin. Code: #include<iostream> using namespace std; void findWaitingTime(int processes[], int n, int bt[], int wt[], int quantum) { int rem_bt[n]; for (int i = 0 ; i < n ; i++) rem_bt[i] = bt[i]; int t = 0; while (1) { bool done = true; for (int i = 0 ; i < n; i++) { if (rem_bt[i] > 0) { done = false; if (rem_bt[i] > quantum) { t += quantum; rem_bt[i] -= quantum; } else { t = t + rem_bt[i]; wt[i] = t - bt[i]; rem_bt[i] = 0; } } } if (done == true) break; } } void findTurnAroundTime(int processes[], int n, int bt[], int wt[], int tat[]) { for (int i = 0; i < n ; i++) tat[i] = bt[i] + wt[i]; } void findavgTime(int processes[], int n, int bt[], int quantum) { int wt[n], tat[n], total_wt = 0, total_tat = 0; findWaitingTime(processes, n, bt, wt, quantum); findTurnAroundTime(processes, n, bt, wt, tat); cout << "PID\t "<< " Burst Time " << "\tWait Ttime " << " \tTurn Around Time\n"; for (int i=0; i<n; i++) { total_wt = total_wt + wt[i]; total_tat = total_tat + tat[i]; cout << " " << i+1 << "\t\t" << bt[i] <<"\t\t" << wt[i] <<"\t\t " << tat[i] <<endl; } cout << "Average waiting time = " << (float)total_wt / (float)n; cout << "\nAverage turn around time = " << (float)total_tat / (float)n << "\n"; } int main() { int processes[] = { 1, 2, 3}; int n = sizeof processes / sizeof processes[0]; int burst_time[] = {10, 5, 8}; int quantum = 2; findavgTime(processes, n, burst_time, quantum); return 0; } Output: Viva Questions: Q1: Name different types of Scheduler. Ans: Schedulers are of three types − Long-Term Scheduler Short-Term Scheduler Medium-Term Scheduler Q2: What is Round Robin Scheduling? Ans: This is the preemptive version of first come first serve scheduling. The Algorithm focuses on Time Sharing. In this algorithm, every process gets executed in a cyclic way. A certain time slice is defined in the system which is called time quantum. Each process present in the ready queue is assigned the CPU for that time quantum, if the execution of the process is completed during that time then the process will terminate else the process will go back to the ready queue and waits for the next turn to complete the execution. Q3: What are advantages of Round Robin Scheduling? Ans: Advantages are: 1. It can be actually implementable in the system because it is not depending on the burst time. 2. It doesn't suffer from the problem of starvation or convoy effect. 3. All the jobs get a fare allocation of CPU. Q4: What are disadvantages of Round Robin Scheduling? Ans: Disadvantages are: 1. The higher the time quantum, the higher the response time in the system. 2. The lower the time quantum, the higher the context switching overhead in the system. 3. Deciding a perfect time quantum is really a very difficult task in the system. EXPERIMENT 8 Aim: Write a program for page replacement policy using a) LRU b) FIFO c) Optimal Code: //LRU #include<bits/stdc++.h> using namespace std; int pageFaults(int pages[], int n, int capacity) { unordered_set<int> s; unordered_map<int, int> indexes; int page_faults = 0; for (int i=0; i<n; i++) { if (s.size() < capacity) { if (s.find(pages[i])==s.end()) { s.insert(pages[i]); page_faults++; } indexes[pages[i]] = i; } else { if (s.find(pages[i]) == s.end()) { int lru = INT_MAX, val; for (auto it=s.begin(); it!=s.end(); it++) { if (indexes[*it] < lru) { lru = indexes[*it]; val = *it; } } s.erase(val); s.insert(pages[i]); page_faults++; } indexes[pages[i]] = i; } } return page_faults; } int main() { cout<< "Program for LRU page replacement algorithm\n"; int n; cout <<"Enter number of pages\n"; cin >> n; cout <<"Enter pages\n"; int pages[n]; for(int i=0;i<n;i++) cin >> pages[i]; cout<<"Enter memory capacity\n"; int capacity; cin >> capacity; cout << "No of page faults=" << pageFaults(pages, n, capacity) << "\n"; return 0; } //FIFO // C++ implementation of FIFO page replacement // in Operating Systems. #include<bits/stdc++.h> using namespace std; int pageFaults(int pages[], int n, int capacity) { unordered_set<int> s; queue<int> indexes; int page_faults = 0; for (int i=0; i<n; i++) { if (s.size() < capacity) { if (s.find(pages[i])==s.end()) { s.insert(pages[i]); page_faults++; indexes.push(pages[i]); } } else { if (s.find(pages[i]) == s.end()) { int val = indexes.front(); indexes.pop(); s.erase(val); s.insert(pages[i]); indexes.push(pages[i]); page_faults++; } } } return page_faults; } int main() { cout<< "Program for FIFO page replacement algorithm\n"; int n; cout <<"Enter number of pages\n"; cin >> n; cout <<"Enter pages\n"; int pages[n]; for(int i=0;i<n;i++) cin >> pages[i]; cout<<"Enter memory capacity\n"; int capacity; cin >> capacity; cout << "No of page faults=" << pageFaults(pages, n, capacity) << "\n"; return 0; } //Optimal #include <bits/stdc++.h> using namespace std; bool search(int key, vector<int>& fr) { for (int i = 0; i < fr.size(); i++) if (fr[i] == key) return true; return false; } int predict(int pg[], vector<int>& fr, int pn, int index) { int res = -1, farthest = index; for (int i = 0; i < fr.size(); i++) { int j; for (j = index; j < pn; j++) { if (fr[i] == pg[j]) { if (j > farthest) { farthest = j; res = i; } break; } } if (j == pn) return i; } return (res == -1) ? 0 : res; } int optimalPage(int pg[], int pn, int fn) { vector<int> fr; int hit = 0; for (int i = 0; i < pn; i++) { if (search(pg[i], fr)) { hit++; continue; } if (fr.size() < fn) fr.push_back(pg[i]); else { int j = predict(pg, fr, pn, i + 1); fr[j] = pg[i]; } } return pn-hit; } int main() { cout<< "Program for Optimal page replacement algorithm\n"; int n; cout <<"Enter number of pages\n"; cin >> n; cout <<"Enter pages\n"; int pages[n]; for(int i=0;i<n;i++) cin >> pages[i]; cout<<"Enter memory capacity\n"; int capacity; cin >> capacity; cout << "No of page faults=" << optimalPage(pages, n, capacity) << "\n"; return 0; } Output: Viva Questions: Q1: What is a page fault? Ans: A page fault happens when a running program accesses a memory page that is mapped into the virtual address space but not loaded in physical memory. Q2: What are Page replacement algorithms? Ans: The page replacement algorithm decides which memory page is to be replaced. The process of replacement is sometimes called swap out or write to disk. Page replacement is done when the requested page is not found in the main memory (page fault). Q3: Name and explain different page replacement algorithms. Ans: 1. Optimal Page Replacement algorithm → this algorithms replaces the page which will not be referred for so long in future. Although it can not be practically implementable but it can be used as a benchmark. Other algorithms are compared to this in terms of optimality. 2. Least recent used (LRU) page replacement algorithm → this algorithm replaces the page which has not been referred for a long time. This algorithm is just opposite to the optimal page replacement algorithm. In this, we look at the past instead of staring at future. 3. FIFO → in this algorithm, a queue is maintained. The page which is assigned the frame first will be replaced first. In other words, the page which resides at the rare end of the queue will be replaced on the every page fault. EXPERIMENT 9 Aim: Write a program to implement first fit, best fit and worst fit algorithm for memory management Code: #include<bits/stdc++.h> using namespace std; void firstFit(int blockSize[], int m, int processSize[], int n) { int allocation[n]; memset(allocation, -1, sizeof(allocation)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (blockSize[j] >= processSize[i]) { allocation[i] = j; blockSize[j] -= processSize[i]; break; } } } cout << "Process No.\tProcess Size\tBlock no.\n"; for (int i = 0; i < n; i++) { cout << " " << i+1 << "\t\t" << processSize[i] << "\t\t"; if (allocation[i] != -1) cout << allocation[i] + 1; else cout << "Not Allocated"; cout << endl; } } void bestFit(int blockSize[], int m, int processSize[], int n) { int allocation[n]; memset(allocation, -1, sizeof(allocation)); for (int i=0; i<n; i++) { int bestIdx = -1; for (int j=0; j<m; j++) { if (blockSize[j] >= processSize[i]) { if (bestIdx == -1) bestIdx = j; else if (blockSize[bestIdx] > blockSize[j]) bestIdx = j; } } if (bestIdx != -1) { allocation[i] = bestIdx; blockSize[bestIdx] -= processSize[i]; } } cout << "Process No.\tProcess Size\tBlock no.\n"; for (int i = 0; i < n; i++) { cout << " " << i+1 << "\t\t" << processSize[i] << "\t\t"; if (allocation[i] != -1) cout << allocation[i] + 1; else cout << "Not Allocated"; cout << endl; } } void worstFit(int blockSize[], int m, int processSize[], int n) { int allocation[n]; memset(allocation, -1, sizeof(allocation)); for (int i=0; i<n; i++) { int wstIdx = -1; for (int j=0; j<m; j++) { if (blockSize[j] >= processSize[i]) { if (wstIdx == -1) wstIdx = j; else if (blockSize[wstIdx] < blockSize[j]) wstIdx = j; } } if (wstIdx != -1) { allocation[i] = wstIdx; blockSize[wstIdx] -= processSize[i]; } } cout << "Process No.\tProcess Size\tBlock no.\n"; for (int i = 0; i < n; i++) { cout << " " << i+1 << "\t\t" << processSize[i] << "\t\t"; if (allocation[i] != -1) cout << allocation[i] + 1; else cout << "Not Allocated"; cout << endl; } } int main() { int m,n; cout << "Enter the number of blocks\n"; cin >> m; int blockSize[m]; cout << "Enter the block sizes\n"; for(int i=0;i<m;i++) cin >> blockSize[i]; cout << "Enter the number of processes\n"; cin >> n; int processSize[n]; cout << "Enter the process sizes\n"; for(int i=0;i<n;i++) cin >> processSize[i]; cout<<"First Fit allocation\n"; firstFit(blockSize, m, processSize, n); cout<<"Best Fit allocation\n"; bestFit(blockSize, m, processSize, n); cout<<"Worst Fit allocation\n"; worstFit(blockSize, m, processSize, n); return 0 ; } Output: Viva Questions: Q1: What is Partition allocation? Ans: In Partition Allocation, when there is more than one partition freely available to accommodate a process’s request, a partition must be selected. To choose a particular partition, a partition allocation method is needed. A partition allocation method is considered better if it avoids internal fragmentation. When it is time to load a process into the main memory and if there is more than one free block of memory of sufficient size then the OS decides which free block to allocate. Q2: Name different placement algorithms. Ans: Different algorithms are: First Fit, Best Fit, Worst Fit, Next Fit Q3: Explain First Fit, Best Fit and Worst Fit algorithms. Ans: 1. First Fit: In the first fit, the partition is allocated which is the first sufficient block from the top of Main Memory. It scans memory from the beginning and chooses the first available block that is large enough. Thus it allocates the first hole that is large enough. 2. Best Fit Allocate the process to the partition which is the first smallest sufficient partition among the free available partition. It searches the entire list of holes to find the smallest hole whose size is greater than or equal to the size of the process. 3. Worst Fit Allocate the process to the partition which is the largest sufficient among the freely available partitions available in the main memory. It is opposite to the best-fit algorithm. It searches the entire list of holes to find the largest hole and allocate it to process. Q4: Which is best among above algorithms and why? Ans: The first fit algorithm is the best algorithm among all because 1. It takes lesser time compare to the other algorithms. 2. It produces bigger holes that can be used to load other processes later on. 3. It is easiest to implement. EXPERIMENT 10 Aim: Write a program to implement reader/writer problem using semaphore Code: #include <pthread.h> #include <semaphore.h> #include <stdio.h> sem_t wrt; pthread_mutex_t mutex; int cnt = 1; int numreader = 0; void *writer(void *wno) { sem_wait(&wrt); cnt = cnt*2; printf("Writer %d modified cnt to %d\n",(*((int *)wno)),cnt); sem_post(&wrt); } void *reader(void *rno) { pthread_mutex_lock(&mutex); numreader++; if(numreader == 1) { sem_wait(&wrt); } pthread_mutex_unlock(&mutex); printf("Reader %d: read cnt as %d\n",*((int *)rno),cnt); pthread_mutex_lock(&mutex); numreader--; if(numreader == 0) { sem_post(&wrt); } pthread_mutex_unlock(&mutex); } int main() { pthread_t read[10],write[5]; pthread_mutex_init(&mutex, NULL); sem_init(&wrt,0,1); int a[10] = {1,2,3,4,5,6,7,8,9,10}; for(int i = 0; i < 10; i++) { pthread_create(&read[i], NULL, (void *)reader, (void *)&a[i]); } for(int i = 0; i < 5; i++) { pthread_create(&write[i], NULL, (void *)writer, (void *)&a[i]); } for(int i = 0; i < 10; i++) { pthread_join(read[i], NULL); } for(int i = 0; i < 5; i++) { pthread_join(write[i], NULL); } pthread_mutex_destroy(&mutex); sem_destroy(&wrt); return 0; } Output: Viva Questions: Q1: What is Semaphore? Ans: Semaphore is a very significant technique to manage concurrent processes by using a simple integer value, which is known as a semaphore. Semaphore is simply an integer variable that is shared between threads. This variable is used to solve the critical section problem and to achieve process synchronization in the multiprocessing environment. Q2: Name Semaphore operations. Ans: A semaphore has two indivisible (atomic) operations, namely: WAIT and SIGNAL . Q3: Name different types Semaphore. Ans: There are two types of semaphores: Binary semaphore Counting Semaphore Q4: What are limitations of Semaphore? Ans: 1. One of the biggest limitations of semaphore is priority inversion. 2. Deadlock, suppose a process is trying to wake up another process which is not in a sleep state. Therefore, a deadlock may block indefinitely. 3. The operating system has to keep track of all calls to wait and to signal the semaphore. EXPERIMENT 11 Aim: Write a program to implement Banker’s algorithm for deadlock avoidance Code: #include<iostream> using namespace std; const int P = 5; const int R = 3; void calculateNeed(int need[P][R], int maxm[P][R], int allot[P][R]) { for (int i = 0 ; i < P ; i++) for (int j = 0 ; j < R ; j++) need[i][j] = maxm[i][j] - allot[i][j]; } bool isSafe(int processes[], int avail[], int maxm[][R], int allot[][R]) { int need[P][R]; calculateNeed(need, maxm, allot); bool finish[P] = {0}; int safeSeq[P]; int work[R]; for (int i = 0; i < R ; i++) work[i] = avail[i]; int count = 0; while (count < P) { bool found = false; for (int p = 0; p < P; p++) { if (finish[p] == 0) { int j; for (j = 0; j < R; j++) if (need[p][j] > work[j]) break; if (j == R) { for (int k = 0 ; k < R ; k++) work[k] += allot[p][k]; safeSeq[count++] = p; finish[p] = 1; found = true; } } } if (found == false) { cout << "System is not in safe state"; return false; } } cout << "System is in safe state.\nSafe" " sequence is: "; for (int i = 0; i < P ; i++) cout << safeSeq[i] << " "; cout << "\n"; return true; } int main() { int processes[] = {0, 1, 2, 3, 4}; int avail[] = {3, 3, 2}; int maxm[][R] = {{7, 5, 3}, {3, 2, 2}, {9, 0, 2}, {2, 2, 2}, {4, 3, 3}}; int allot[][R] = {{0, 1, 0}, {2, 0, 0}, {3, 0, 2}, {2, 1, 1}, {0, 0, 2}}; cout << "The processes are\n"; for(int i =0;i<5;i++) cout << processes[i] <<" "; cout << "\nThe vailable resources are\n"; for(int i =0;i<3;i++) cout << avail[i] <<" "; cout << "\nMaximum Allocation Matrix\n"; for(int i =0;i<5;i++) { for(int j=0;j<3;j++) cout << maxm[i][j] <<" "; cout << "\n"; } cout << "\nAllocated Resources Matrix\n"; for(int i =0;i<5;i++) { for(int j=0;j<3;j++) cout << allot[i][j] <<" "; cout << "\n"; } isSafe(processes, avail, maxm, allot); return 0; } Output: Viva Questions: Q1: How process in an OS uses resources? Ans: A process in operating system uses resources in the following way: 1) Requests a resource 2) Use the resource 3) Releases the resource Q2: What is a Deadlock? Ans: Deadlock is a situation where a set of processes are blocked because each process is holding a resource and waiting for another resource acquired by some other process. Q3: What is Bankers’s Algorithm? Ans: The banker’s algorithm is a resource allocation and deadlock avoidance algorithm that tests for safety by simulating the allocation for predetermined maximum possible amounts of all resources, then makes an “s-state” check to test for possible activities, before deciding whether allocation should be allowed to continue.