0% found this document useful (0 votes)
18 views

OS File

Uploaded by

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

OS File

Uploaded by

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

Department of computer Science & Engineering

KCC INSTITUTE OF TECHNOLOGY &


MANAGEMENT
2B-2C, Knowledge Park-III, Greater Noida, Uttar Pradesh

BCS401-Operating System
LAB FILE
(2023-24)
TH
4 SEMESTER

SUBMITTED TO: SUBMITTEDBY:


Mr. Deepika Kataria Student Name: Ankit
Dept. of CSE B.Tech./CSE CORE (4th Sem)
Univ. Roll No.: 2204920100022
Section: B1
Serial no. 11
Index
Sr. Page
Name of the experiment Date
No. No.
1
Practical-I

Study of hardware and software requirements of different


operating systems (UNIX,LINUX,WINDOWS XP, WINDOWS7/8

 Unix:
 Hardware Requirements: UNIX-like systems have traditionally been known for their flexibility
to run on various hardware architectures, including x86, ARM, SPARC, and others. The hardware
requirements can vary significantly depending on the specific UNIX variant and its intended use
case. Generally, UNIX systems can run on relatively modest hardware configurations, making
them suitable for both low-power devices and high-performance servers.
 Software Requirements: UNIX typically requires a compatible kernel along with a set of system
utilities and libraries. Additionally, specific software packages may be needed based on the UNIX
variant and the user's requirements. UNIX systems are highly customizable, allowing users to
install and configure only the software they need, which contributes to their efficiency and
stability.
 Linux:
 Hardware Requirements: Linux distributions are known for their wide hardware support,
enabling them to run on a vast array of devices, from embedded systems to supercomputers. The
hardware requirements can vary significantly depending on the chosen distribution and the
intended use case. Many modern Linux distributions can run efficiently on relatively low-spec
hardware, making them suitable for older computers and resource-constrained devices.
 Software Requirements: Linux requires a compatible kernel, which serves as the core of the
operating system. In addition to the kernel, Linux distributions come with a vast selection of
software packages, including desktop environments, system utilities, development tools, and
server applications. Users have the flexibility to customize their Linux systems by installing or
removing software packages according to their needs.
 Windows XP:
 Hardware Requirements: Windows XP was released in 2001 and has relatively modest
hardware requirements compared to modern operating systems. The minimum hardware
requirements for Windows XP include a Pentium 233-megahertz (MHz) processor or faster, 64
MB of RAM (although 128 MB or higher is recommended), and at least 1.5 GB of available hard
disk space. However, for optimal performance, higher specifications are recommended,
especially for multitasking and running modern software.
 Software Requirements: Windows XP comes with its kernel and a suite of essential system
utilities and drivers. Users can install additional software applications based on their
requirements, such as productivity software, multimedia applications, and security tools.
 Windows 7/8:
 Hardware Requirements: Windows 7 and 8 have higher hardware requirements compared to
Windows XP due to their more advanced features and improved graphical capabilities. The
recommended hardware specifications for Windows 7 and 8 include a modern CPU (1 GHz or
faster), 1 GB (32-bit) or 2 GB (64-bit) of RAM, and at least 16 GB (32-bit) or 20 GB (64-bit) of
available hard disk space. Higher specifications may be needed for optimal performance,
especially for running demanding software and multitasking.
 Software Requirements: Similar to Windows XP, Windows 7 and 8 come with their kernels,
system utilities, and drivers. Users can install additional software applications from the
Windows Store or third-party sources to enhance functionality and productivity.

Practical-II

Execute various UNIX system calls for i. Process management


ii. File management iii. Input/output Systems calls

(i). Process Management:


1. fork(): Creates a new process by duplicating the current process. The new process is called
the child process, and it has an exact copy of the parent process's memory space.

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

int main() {
pid_t pid = fork();
if (pid == 0) {
// Child process
printf("Child process created.\n");
} else if (pid > 0) {
// Parent process
printf("Parent process. Child PID: %d\n", pid);
} else {
// Error
perror("fork");
}
return 0;
}
2. exec(): Replaces the current process with a new process image. There are variants of the exec()
family, such as execl(), execv(), etc., allowing different ways to pass arguments to the new
process.

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

int main() {
execl("/bin/ls", "ls", "-l", NULL);
perror("exec");
return 0;
}

3. wait(): Suspends execution of the calling process until one of its child processes terminates.

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

int main() {
pid_t pid = fork();
if (pid == 0) {
// Child process
printf("Child process executing.\n");
sleep(2); // Simulate some work
return 0;
} else if (pid > 0) {
// Parent process
printf("Parent process waiting for child to finish.\n");
wait(NULL);
printf("Child process finished.\n");
} else {
// Error
perror("fork");
}
return 0;
}
ii. File Management:
1. open(): Opens a file and returns a file descriptor.

#include <fcntl.h>
#include <stdio.h>

int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
printf("File opened successfully. File Descriptor: %d\n", fd);
close(fd);
return 0;
}

2. read(): Reads data from an open file descriptor into a buffer.

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

int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}

char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == -1) {
perror("read");
return 1;
}
printf("Read %zd bytes: %s\n", bytes_read, buffer);

close(fd);
return 0;
}
iii. Input/Output System Calls:
1. write(): Writes data from a buffer to a file descriptor.

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

int main() {
int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC,
0644); if (fd == -1) {
perror("open");
return 1;
}

const char *text = "Hello, world!\n";


ssize_t bytes_written = write(fd, text,
strlen(text)); if (bytes_written == -1) {
perror("write");
return 1;
}
printf("Wrote %zd bytes.\n", bytes_written);

close(fd);
return 0;
}

Practical-III

Implement CPU Scheduling Policies:

i. SJF
#include <stdio.h>

void sjf(int processes[], int n, int burst_time[]) {


int waiting_time[n], turnaround_time[n], total_waiting_time = 0,
total_turnaround_time = 0;

// Sort processes by burst time


for (int i = 0; i < n; i++) {
int min_index = i;
for (int j = i + 1; j < n; j++) {
if (burst_time[j] < burst_time[min_index])
min_index = j;
}
// Swap burst time
int temp = burst_time[min_index];
burst_time[min_index] = burst_time[i];
burst_time[i] = temp;
// Swap processes
temp = processes[min_index];
processes[min_index] = processes[i];
processes[i] = temp;
}

waiting_time[0] = 0;

// Calculate waiting time


for (int i = 1; i < n; i++) {
waiting_time[i] = burst_time[i - 1] + waiting_time[i - 1];
total_waiting_time += waiting_time[i];
}

// Calculate turnaround time


for (int i = 0; i < n; i++) {
turnaround_time[i] = burst_time[i] + waiting_time[i];
total_turnaround_time += turnaround_time[i];
}

// Print results
printf("Process ID\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t\t%d\t\t%d\t\t%d\n", processes[i], burst_time[i], waiting_time[i],
turnaround_time[i]);
}

// Print average waiting and turnaround time


printf("Average Waiting Time: %f\n", (float)total_waiting_time / n);
printf("Average Turnaround Time: %f\n", (float)total_turnaround_time / n);
}

int main() {
int processes[] = {1, 2, 3, 4};
int n = sizeof(processes) / sizeof(processes[0]);
int burst_time[] = {6, 8, 7, 3};

sjf(processes, n, burst_time);

return 0;
}
ii. Priority
#include <stdio.h>

void priority_scheduling(int processes[], int n, int burst_time[], int priority[]) { int


waiting_time[n], turnaround_time[n], total_waiting_time = 0,
total_turnaround_time = 0;

// Sort processes by priority


for (int i = 0; i < n; i++) {
int max_index = i;
for (int j = i + 1; j < n; j++) {
if (priority[j] < priority[max_index])
max_index = j;
}
// Swap priority
int temp = priority[max_index];
priority[max_index] = priority[i];
priority[i] = temp;

// Swap burst time


temp = burst_time[max_index];
burst_time[max_index] = burst_time[i];
burst_time[i] = temp;

// Swap processes
temp = processes[max_index];
processes[max_index] = processes[i];
processes[i] = temp;
}

waiting_time[0] = 0;
// Calculate waiting time
for (int i = 1; i < n; i++) {
waiting_time[i] = burst_time[i - 1] + waiting_time[i - 1];
total_waiting_time += waiting_time[i];
}

// Calculate turnaround time


for (int i = 0; i < n; i++) {
turnaround_time[i] = burst_time[i] + waiting_time[i];
total_turnaround_time += turnaround_time[i];
}

// Print results
printf("Process ID\tBurst Time\tPriority\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n", processes[i], burst_time[i], priority[i],
waiting_time[i], turnaround_time[i]);
}

// Print average waiting and turnaround time


printf("Average Waiting Time: %f\n", (float)total_waiting_time / n);
printf("Average Turnaround Time: %f\n", (float)total_turnaround_time / n);
}

int main() {
int processes[] = {1, 2, 3, 4};
int n = sizeof(processes) / sizeof(processes[0]);
int burst_time[] = {6, 8, 7, 3};
int priority[] = {2, 1, 3, 4};

priority_scheduling(processes, n, burst_time, priority);

return 0;
}
iii. FCFS

#include <stdio.h>

void fcfs(int processes[], int n, int burst_time[]) {


int waiting_time[n], turnaround_time[n], total_waiting_time = 0,
total_turnaround_time = 0;

waiting_time[0] = 0;

// Calculate waiting time


for (int i = 1; i < n; i++) {
waiting_time[i] = burst_time[i - 1] + waiting_time[i - 1];
total_waiting_time += waiting_time[i];
}

// Calculate turnaround time


for (int i = 0; i < n; i++) {
turnaround_time[i] = burst_time[i] + waiting_time[i];
total_turnaround_time += turnaround_time[i];
}

// Print results
printf("Process ID\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t\t%d\t\t%d\t\t%d\n", processes[i], burst_time[i], waiting_time[i],
turnaround_time[i]);
}

// Print average waiting and turnaround time


printf("Average Waiting Time: %f\n", (float)total_waiting_time / n);
printf("Average Turnaround Time: %f\n", (float)total_turnaround_time / n);
}
int main() {
int processes[] = {1, 2, 3, 4};
int n = sizeof(processes) / sizeof(processes[0]);
int burst_time[] = {6, 8, 7, 3};

fcfs(processes, n, burst_time);

return 0;
}

iv. Multi-level Queue

##include <stdio.h>

#define MAX_PROCESS 100

// Structure to represent a process


struct Process {
int id; // Process ID
int burst_time; // Burst time
};

// Function to perform multi-level queue scheduling


void multi_level_queue(struct Process processes[], int n) {
// Initialize queues
struct Process queue1[MAX_PROCESS], queue2[MAX_PROCESS];
int front1 = -1, rear1 = -1, front2 = -1, rear2 = -1;

// Quantum time for the second queue


int quantum = 4;

// Separate processes into two queues based on their burst time


for (int i = 0; i < n; i++) {
if (processes[i].burst_time <= quantum)
queue1[++rear1] = processes[i];
else
queue2[++rear2] = processes[i];
}

// Current time
int current_time = 0;

// Process each queue


printf("Process ID\tBurst Time\tWaiting Time\tTurnaround Time\n");
while (front1 <= rear1 || front2 <= rear2) {
// Process queue 1
while (front1 <= rear1) {
struct Process p = queue1[front1++];
printf("%d\t\t%d\t\t%d\t\t%d\n", p.id, p.burst_time, current_time, current_time
+ p.burst_time);
current_time += p.burst_time;
}

// Process queue 2
while (front2 <= rear2) {
struct Process p = queue2[front2++];
printf("%d\t\t%d\t\t%d\t\t%d\n", p.id, p.burst_time, current_time, current_time
+ quantum);
current_time += quantum;
p.burst_time -= quantum;
if (p.burst_time > 0)
queue2[++rear2] = p; // Requeue the process if burst time remains
else
printf("%d\t\t%d\t\t%d\t\t%d\n", p.id, p.burst_time, current_time,
current_time - p.burst_time);
}
}
}

int main() {
// Example processes
struct Process processes[] = {{1, 6}, {2, 8}, {3, 7}, {4, 3}}; int
n = sizeof(processes) / sizeof(processes[0]);

// Perform multi-level queue scheduling


multi_level_queue(processes, n);
return 0;
}

Practical-IV

4. Implement file storage allocation technique:


.

(i). Contiguous Allocation (Using Array):

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

#define MAX_FILES 100


#define MAX_BLOCKS 1000

struct File {
int start_block;
int length;
};

struct File files[MAX_FILES]; // Array to store file information


int disk[MAX_BLOCKS]; // Array representing disk blocks (0 for free, 1 for allocated)

int allocate_contiguous(int file_size) {


int start_block = -1;

// Find contiguous free blocks for the file


for (int i = 0; i < MAX_BLOCKS - file_size + 1; i++)
{ int j;
for (j = 0; j < file_size; j++)
{ if (disk[i + j] != 0) {
break; // Not contiguous, move to the next block
}
}
if (j == file_size)
{ start_block =
i;
break; // Found contiguous free blocks
}
}

// Allocate blocks for the


file if (start_block != -1) {
for (int i = start_block; i < start_block + file_size; i++)
{ disk[i] = 1; // Mark blocks as allocated
}
}

return start_block;
}

void display_disk_status() {
printf("Disk Status:\n");
for (int i = 0; i < MAX_BLOCKS; i++)
{ printf("%d ", disk[i]);
}
printf("\n\n");
}

int main() {
// Initialize disk blocks (0 for free)
for (int i = 0; i < MAX_BLOCKS; i++)
{ disk[i] = 0;
}

// Example file allocation


int file_sizes[] = {5, 3, 4}; // File sizes
int num_files = sizeof(file_sizes) / sizeof(file_sizes[0]);

printf("File Allocation:\n");
for (int i = 0; i < num_files; i++) {
int start_block = allocate_contiguous(file_sizes[i]);
if (start_block != -1) {
files[i].start_block = start_block;
files[i].length = file_sizes[i];
printf("File %d: Allocated from block %d to %d\n", i + 1, start_block, start_block + file_sizes[i] - 1);
} else {
printf("File %d: Not enough contiguous free space\n", i + 1);
}
display_disk_status();
}

return 0;
}
(ii).Linked List Allocation:

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

struct Node {
int block;
struct Node* next;
};

struct File {
struct Node* start;
int length;
};

struct File files[100]; // Array to store file information

void allocate_linked_list(int file_size, int file_index) {


struct Node* head = NULL;

// Allocate blocks for the file


for (int i = 0; i < file_size; i++) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->block = i;
new_node->next = NULL;

if (head == NULL)
{ files[file_index].start =
new_node; head = new_node;
} else {
head->next = new_node;
head = head->next;
}
}

files[file_index].length = file_size;
}
void display_linked_list(int file_index) {
struct Node* current = files[file_index].start;

printf("File %d: ", file_index + 1);


while (current != NULL) {
printf("%d ", current->block);
current = current->next;
}
printf("\n\n");
}

int main() {
// Example file allocation
int file_sizes[] = {5, 3, 4}; // File sizes
int num_files = sizeof(file_sizes) / sizeof(file_sizes[0]);

printf("File Allocation:\n");
for (int i = 0; i < num_files; i++)
{ allocate_linked_list(file_sizes[i], i);
printf("File %d: Allocated blocks: ", i + 1);
display_linked_list(i);
}

return 0;
}

(iii). Indirect Allocation (Indexing):

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

#define MAX_BLOCKS 1000


#define BLOCK_SIZE 10
#define INDEX_BLOCK_SIZE 10

struct File {
int index_block[INDEX_BLOCK_SIZE];
int length;
};

struct File files[100]; // Array to store file information

void allocate_indirect_indexing(int file_size, int file_index) {


// Calculate number of blocks needed for the index block
int num_index_blocks = file_size / BLOCK_SIZE;
if (file_size % BLOCK_SIZE != 0)
num_index_blocks++;

// Allocate blocks for the file and store block numbers in index block
for (int i = 0; i < num_index_blocks; i++) {
files[file_index].index_block[i] = i + 1; // Assuming blocks start from 1
}

files[file_index].length = file_size;
}

void display_indirect_indexing(int file_index)


{ printf("File %d: ", file_index + 1);
for (int i = 0; i < files[file_index].length / BLOCK_SIZE; i++)
{ printf("%d ", files[file_index].index_block[i]);
}
printf("\n\n");
}

int main() {
// Example file allocation
int file_sizes[] = {25, 35, 15}; // File sizes
int num_files = sizeof(file_sizes) / sizeof(file_sizes[0]);

printf("File Allocation:\n");
for (int i = 0; i < num_files; i++)
{ allocate_indirect_indexing(file_sizes[i], i);
printf("File %d: Allocated blocks: ", i + 1);
display_indirect_indexing(i);
}

return 0;
}
PRACTICAL V

Implementation of contiguous allocation techniques:

i. Worst-Fit

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

#define MAX_BLOCKS 100

struct IndexBlock {
int pointers[MAX_BLOCKS];
};

struct File {
int size;
struct IndexBlock* index;
};

void initializeIndexBlock(struct IndexBlock* block) {


for (int i = 0; i < MAX_BLOCKS; ++i) {
block->pointers[i] = -1;
}
}

void allocateBlocks(struct File* file, int numBlocks) {


if (file->size + numBlocks > MAX_BLOCKS)
{ printf("Not enough space for allocation.\n");
return;
}

if (file->index == NULL) {
file->index = (struct IndexBlock*)malloc(sizeof(struct
IndexBlock)); initializeIndexBlock(file->index);
}

for (int i = 0; i < numBlocks; ++i) {


for (int j = 0; j < MAX_BLOCKS; ++j) {
if (file->index->pointers[j] == -1) {
file->index->pointers[j] = file->size +
i; break;
}
}
}

file->size += numBlocks;
}

int main() {
struct File myFile;
myFile.size = 0;
myFile.index = NULL;

allocateBlocks(&myFile, 5); // Allocate 5

blocks printf("Allocated blocks: ");


for (int i = 0; i < MAX_BLOCKS; ++i) {
if (myFile.index->pointers[i] != -1) {
printf("%d ", myFile.index->pointers[i]);
}
}
printf("\n");

free(myFile.index);
return 0;
}

ii. Best- Fit

#include <stdio.h>

void bestFit(int blockSize[], int m, int processSize[], int n)


{ int allocation[n];
for (int i = 0; i < n; i++)
allocation[i] = -1;

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];
}
}

printf("\nProcess No.\tProcess Size\tBlock no.\n");


for (int i = 0; i < n; i++) {
printf(" %d\t\t%d\t\t", i + 1,
processSize[i]); if (allocation[i] != -1)
printf("%d", allocation[i] + 1);
else
printf("Not Allocated"); printf("\
n");
}
}

int main() {
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426};
int m = sizeof(blockSize) / sizeof(blockSize[0]);
int n = sizeof(processSize) /
sizeof(processSize[0]); bestFit(blockSize, m,
processSize, n);
return 0;
}

iii. First- Fit

#include <stdio.h>

void firstFit(int blockSize[], int m, int processSize[], int n)


{ int allocation[n];
for (int i = 0; i < n; i++)
allocation[i] = -1;

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;
}
}
}

printf("\nProcess No.\tProcess Size\tBlock no.\n");


for (int i = 0; i < n; i++) {
printf(" %d\t\t%d\t\t", i + 1,
processSize[i]); if (allocation[i] != -1)
printf("%d", allocation[i] + 1);
else
printf("Not Allocated"); printf("\
n");
}
}

int main() {
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426};
int m = sizeof(blockSize) / sizeof(blockSize[0]);
int n = sizeof(processSize) /
sizeof(processSize[0]); firstFit(blockSize, m,
processSize, n);
return 0;
}
PRACTICAL VI
Calculation of external and internal fragmentation i. Free space list of blocks from system ii.
List process file from the system

Let’s write a simple C program that demonstrates external and internal fragmentation using contiguous allocation
techniques (Worst-Fit, Best-Fit, and First-Fit). We’ll assume fixed-sized memory blocks for simplicity:
#include <stdio.h>

// Define memory block size (in KB)


#define BLOCK_SIZE 100

// Structure to represent a memory block


struct Block {
int id; // Process ID (0 for free
blocks) int size; // Size of the block
};

// Initialize memory blocks


struct Block memory[6] = {
{0, 50}, {0, 400}, {0, 130}, {0, 300}, {0, 150}, {0, 70}
};

// Allocate memory using First-Fit


void allocateFirstFit(int processId, int processSize)
{ for (int i = 0; i < 6; ++i) {
if (memory[i].id == 0 && memory[i].size >= processSize)
{ memory[i].id = processId;
memory[i].size -= processSize;
break;
}
}
}

// Print memory status


void printMemory() {
printf("Memory Status:\n");
for (int i = 0; i < 6; ++i) {
printf("Block %d: %d KB (Process %d)\n", i, memory[i].size, memory[i].id);
}
}

int main() {
// Example processes
allocateFirstFit(1, 230);
allocateFirstFit(2, 180);
allocateFirstFit(3, 130);
allocateFirstFit(4, 120);
allocateFirstFit(5, 200);

// Print memory status


printMemory();

return 0;
}
PRACTICAL VII

Implementation of compaction for the continually changing memory layout and calculate
total movement of data

#include <stdio.h>

// Define memory block size (in KB)


#define BLOCK_SIZE 100

// Structure to represent a memory block


struct Block {
int id; // Process ID (0 for free
blocks) int size; // Size of the block
};

// Initialize memory blocks


struct Block memory[6] = {
{0, 50}, {0, 400}, {0, 130}, {0, 300}, {0, 150}, {0, 70}
};

// Allocate memory using First-Fit


void allocateFirstFit(int processId, int processSize)
{ for (int i = 0; i < 6; ++i) {
if (memory[i].id == 0 && memory[i].size >= processSize)
{ memory[i].id = processId;
memory[i].size -= processSize;
break;
}
}
}

// Compact memory by moving processes up


void compactMemory() {
int nextFreeBlock = 0;
for (int i = 0; i < 6; ++i)
{
if (memory[i].id != 0) {
memory[nextFreeBlock] = memory[i];
++nextFreeBlock;
}
}
// Reset remaining blocks
for (int i = nextFreeBlock; i < 6; ++i)
{ memory[i].id = 0;
memory[i].size = BLOCK_SIZE;
}
}

// Print memory status


void printMemory() {
printf("Memory Status:\n");
for (int i = 0; i < 6; ++i) {
printf("Block %d: %d KB (Process %d)\n", i, memory[i].size, memory[i].id);
}
}

int main() {
// Example processes
allocateFirstFit(1, 230);
allocateFirstFit(2, 180);
allocateFirstFit(3, 130);
allocateFirstFit(4, 120);
allocateFirstFit(5, 200);

// Compact memory
compactMemory();

// Print memory status after compaction


printMemory();

return 0;
}

PRACTICAL VIII

Implementation of resource allocation graph RAG)

#include <stdio.h>
#include <stdbool.h>

#define MAX_PROCESSES 10
#define MAX_RESOURCES 10

bool resource_allocation_graph[MAX_PROCESSES][MAX_RESOURCES];
int num_processes, num_resources;

// Function for checking cycles using Depth First Search (DFS)


bool is_cycle_util(int process, bool visited[], bool stack[]) {
if (!visited[process]) {
visited[process] = true;
stack[process] = true;
for (int i = 0; i < num_resources; ++i) {
if (resource_allocation_graph[process][i]) {
if (!visited[i] && is_cycle_util(i, visited, stack))
{ return true;
} else if (stack[i])
{ return true;
}
}
}
}
stack[process] = false;
return false;
}

// Function for detecting cycle in the graph


bool has_cycle() {
bool visited[MAX_PROCESSES] =
{false}; bool stack[MAX_PROCESSES] =
{false}; for (int i = 0; i < num_processes; +
+i) {
if (is_cycle_util(i, visited, stack))
{ return true;
}
}
return false;
}

int main() {
// Enter processes and resources
printf("Enter the number of processes: ");
scanf("%d", &num_processes);
printf("Enter the number of resources: ");
scanf("%d", &num_resources);

// Input resource allocation graph


printf("Enter the resource allocation graph (1 if process i is allocated resource j, 0 otherwise):\n");
for (int i = 0; i < num_processes; ++i) {
for (int j = 0; j < num_resources; ++j) {
scanf("%d", &resource_allocation_graph[i][j]);
}
}

// Checking for cycle


if (has_cycle()) {
printf("Deadlock detected! Found cycle in the resource allocation graph.\n");
} else {
printf("No deadlock detected. Resource allocation graph is deadlock free.\n");
}

return 0;
}
PRACTICAL IX

Implementation of Banker‟s algorithm

// C++ program to illustrate Banker's Algorithm


#include<iostream>
using namespace std;

// Number of
processes const int P =
5;

// Number of
resources const int R
= 3;

// Function to find the need of each process


void calculateNeed(int need[P][R], int maxm[P][R],
int allot[P][R])
{
// Calculating Need of each P
for (int i = 0 ; i < P ; i++)
for (int j = 0 ; j < R ; j++)

// Need of instance = maxm instance -


// allocated instance
need[i][j] = maxm[i][j] - allot[i][j];
}

// Function to find the system is in safe state or not


bool isSafe(int processes[], int avail[], int maxm[][R],
int allot[][R])
{
int need[P][R];

// Function to calculate need matrix


calculateNeed(need, maxm, allot);

// Mark all processes as infinish


bool finish[P] = {0};

// To store safe
sequence int
safeSeq[P];

// Make a copy of available resources


int work[R];
for (int i = 0; i < R ; i++)
work[i] = avail[i];

// While all processes are not finished


// or system is not in safe state.
int count = 0;
while (count < P)
{
// Find a process which is not finish and
// whose needs can be satisfied with current
// work[] resources.
bool found = false;
for (int p = 0; p < P; p++)
{
// First check if a process is finished,
// if no, go for next condition
if (finish[p] == 0)
{
// Check if for all resources of
// current P need is less
// than work
int j;
for (j = 0; j < R; j++)
if (need[p][j] > work[j])
break;

// If all needs of p were satisfied.


if (j == R)
{
// Add the allocated resources of
// current P to the available/work
// resources i.e.free the
resources for (int k = 0 ; k < R ;
k++)
work[k] += allot[p][k];

// Add this process to safe sequence.


safeSeq[count++] = p;

// Mark this p as finished


finish[p] = 1;

found = true;
}
}
}

// If we could not find a next process in safe


// sequence.
if (found == false)
{
cout << "System is not in safe state";
return false;
}
}

// If system is in safe state then


// safe sequence will be as below
cout << "System is in safe state.\
nSafe" " sequence is: ";
for (int i = 0; i < P ; i++)
cout << safeSeq[i] << " ";

return true;
}

// Driver code
int main()
{
int processes[] = {0, 1, 2, 3, 4};

// Available instances of
resources int avail[] = {3, 3, 2};

// Maximum R that can be allocated


// to processes
int maxm[][R] = {{7, 5, 3},
{3, 2, 2},
{9, 0, 2},
{2, 2, 2},
{4, 3, 3}};

// Resources allocated to
processes int allot[][R] = {{0, 1,
0},
{2, 0, 0},
{3, 0, 2},
{2, 1, 1},
{0, 0, 2}};

// Check system is in safe state or not


isSafe(processes, avail, maxm, allot);
return 0;
}

PRACTICAL X

Conversion of resource allocation graph (RAG) to wait for graph (WFG) for each type
of method used for storing graph

RAG Representation (Contiguous Allocation)

#include <stdio.h>

#define P 5 // Number of processes


#define R 3 // Number of resources

// Function to convert RAG to WFG


void convertRAGtoWFG(int rag[P+R][P+R], int wfg[P][P])
{ for (int i = 0; i < P; i++) {
for (int j = 0; j < P; j++) { wfg[i]
[j] = 0; // Initialize WFG
}
}

for (int i = 0; i < P; i++) {


for (int j = P; j < P + R; j++) {
if (rag[i][j]) { // If process i is waiting for resource j-P
for (int k = 0; k < P; k++) {
if (rag[j][k]) { // If resource j-P is allocated to process k wfg[i]
[k] = 1; // Process i is waiting for process k
}
}
}
}
}
}

// Function to display the graph


void displayGraph(int graph[P][P])
{ for (int i = 0; i < P; i++) {
for (int j = 0; j < P; j++) {
printf("%d ", graph[i][j]);
}
printf("\n");
}
}

int main() {
// Initialize RAG
int rag[P + R][P + R] = {0};

// Example: Process 0 requests Resource 0 and Resource 0 is allocated to Process 1


rag[0][P] = 1; // P0 -> R0
rag[P][1] = 1; // R0 -> P1

// Example: Process 2 requests Resource 1 and Resource 1 is allocated to Process 3


rag[2][P + 1] = 1; // P2 -> R1
rag[P + 1][3] = 1; // R1 -> P3

// Initialize WFG
int wfg[P][P];

// Convert RAG to WFG


convertRAGtoWFG(rag, wfg);

// Display WFG
printf("Wait-For Graph (WFG):\
n"); displayGraph(wfg);

return 0;
}
RAG

Representation (Linked-List Allocation)

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

#define P 5 // Number of processes


#define R 3 // Number of resources

typedef struct Node


{ int process;
struct Node* next;
} Node;

// Function to add an edge to the adjacency list


void addEdge(Node* graph[], int u, int v) {
Node* newNode =
(Node*)malloc(sizeof(Node)); newNode-
>process = v;
newNode->next = graph[u];
graph[u] = newNode;
}

// Function to convert RAG to WFG


void convertRAGtoWFG(Node* rag[], Node* wfg[])
{ for (int i = 0; i < P; i++) {
wfg[i] = NULL; // Initialize WFG
}

for (int i = 0; i < P; i++)


{ Node* temp = rag[i];
while (temp) {
int resource = temp->process - P;
Node* tempResource = rag[resource + P];
while (tempResource) {
addEdge(wfg, i, tempResource->process);
tempResource = tempResource->next;
}
temp = temp->next;
}
}
}

// Function to display the graph


void displayGraph(Node* graph[], int size)
{ for (int i = 0; i < size; i++) {
Node* temp = graph[i];
printf("%d -> ", i);
while (temp) {
printf("%d ", temp->process);
temp = temp->next;
}
printf("\n");
}
}

int main() {
// Initialize RAG
Node* rag[P + R] = {NULL};

// Example: Process 0 requests Resource 0 and Resource 0 is allocated to Process 1


addEdge(rag, 0, P); // P0 -> R0
addEdge(rag, P, 1); // R0 -> P1

// Example: Process 2 requests Resource 1 and Resource 1 is allocated to Process 3


addEdge(rag, 2, P + 1); // P2 -> R1
addEdge(rag, P + 1, 3); // R1 -> P3

// Initialize WFG
Node* wfg[P] = {NULL};

// Convert RAG to WFG


convertRAGtoWFG(rag, wfg);

// Display WFG
printf("Wait-For Graph (WFG):\
n"); displayGraph(wfg, P);

return 0;
}

RAG Representation (Indirect Allocation)

#include <stdio.h>

#define P 5 // Number of processes


#define R 3 // Number of resources

// Function to convert RAG to WFG


void convertRAGtoWFG(int rag[P + R][P + R], int wfg[P][P]) {
for (int i = 0; i < P; i++) {
for (int j = 0; j < P; j++) {
wfg[i][j] = 0; // Initialize WFG
}
}

for (int i = 0; i < P; i++) {


for (int j = P; j < P + R; j++) {
if (rag[i][j]) { // If process i is waiting for resource j-P
for (int k = 0; k < P; k++) {
if (rag[j][k]) { // If resource j-P is allocated to process k wfg[i]
[k] = 1; // Process i is waiting for process k
}
}
}
}
}
}

// Function to display the graph


void displayGraph(int graph[P][P])
{ for (int i = 0; i < P; i++) {
for (int j = 0; j < P; j++) {
printf("%d ", graph[i][j]);
}
printf("\n");
}
}

int main() {
// Initialize RAG
int rag[P + R][P + R] = {0};

// Example: Process 0 requests Resource 0 and Resource 0 is allocated to Process 1


rag[0][P] = 1; // P0 -> R0
rag[P][1] = 1; // R0 -> P1

// Example: Process 2 requests Resource 1 and Resource 1 is allocated to Process 3


rag[2][P + 1] = 1; // P2 -> R1
rag[P + 1][3] = 1; // R1 -> P3

// Initialize WFG
int wfg[P][P];

// Convert RAG to WFG


convertRAGtoWFG(rag, wfg);

// Display WFG
printf("Wait-For Graph (WFG):\
n"); displayGraph(wfg);

return 0;
}
PRACTICAL XI
Implement the solution for Bounded Buffer (producer-consumer)problem using inter process
communication techniques-Semaphores
PRACTICAL XII

Implement the solutions for Readers-Writers problem using inter process


communication technique -Semaphore

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>

sem_t mutex,writeblock;
int data = 0,rcount = 0;

void *reader(void *arg)


{
int f;
f = ((int)arg);
sem_wait(&mutex);
rcount = rcount + 1;
if(rcount==1)
sem_wait(&writeblock);
sem_post(&mutex);
printf("Data read by the reader%d is %d\n",f,data);
sleep(1);
sem_wait(&mutex);
rcount = rcount - 1;
if(rcount==0)
sem_post(&writeblock);
sem_post(&mutex);
}

void *writer(void *arg)


{
int f;
f = ((int) arg);
sem_wait(&writeblock);
data++;
printf("Data writen by the writer%d is %d\n",f,data);
sleep(1);
sem_post(&writeblock);
}

int main()
{
int i,b;
pthread_t rtid[5],wtid[5];
sem_init(&mutex,0,1);
sem_init(&writeblock,0,1);
for(i=0;i<=2;i++)
{
pthread_create(&wtid[i],NULL,writer,(void *)i);
pthread_create(&rtid[i],NULL,reader,(void *)i);
}
for(i=0;i<=2;i++)
{
pthread_join(wtid[i],NULL);
pthread_join(rtid[i],NULL);
}
return 0;
}

You might also like