0% found this document useful (0 votes)
28 views62 pages

OS Practical

The document outlines a practical lab report by Aanya Singh, detailing various operating system experiments including CPU scheduling policies (SJF, Priority, FCFS, Multi-level queue) and file storage allocation techniques (Contiguous, Linked, Indexed). Each experiment includes code snippets demonstrating the implementation of these concepts. The report also includes an index of practicals with completion and submission dates.

Uploaded by

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

OS Practical

The document outlines a practical lab report by Aanya Singh, detailing various operating system experiments including CPU scheduling policies (SJF, Priority, FCFS, Multi-level queue) and file storage allocation techniques (Contiguous, Linked, Indexed). Each experiment includes code snippets demonstrating the implementation of these concepts. The report also includes an index of practicals with completion and submission dates.

Uploaded by

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

OS LAB PRACTICAL

FILE
Name – Aanya Singh
Registration Number – 23BCE10956
Slot – A14+D11+D12
INDEX: -
Sr Title Practical Date of Date of Sign
No. number completion submission
1 Study of 1 3-12-24 16-12-24
Hardware/Software
requirement of
various operating
system.
2 Implement CPU 2 3-12-24 16-12-24
scheduling policies
3 File Storage 3 3-12-24 16-12-24
Allocation
Techniques
4 Contiguous 4 5-12-24 16-12-24
Allocation
Techniques
5 External and 5 5-12-24 16-12-24
Internal
Fragmentation
6 External and 6 5-12-24 16-12-24
Internal
Fragmentation
7 Resource 7 8-12-24 16-12-24
Allocation Graph
(RAG)
8 Bankers Algorithm 8 12-12-24 16-12-24
9 Wait Graph 9 12-12-24 16-12-24
10 Inter process 10 12-12-24 16-12-24
Communication –
Semaphore
11 FORK and JOIN 11 12-12-24 16-12-24
construct
EXPERIMENT – 1:-
AIM:Defining function inside class

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

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

if (pid < 0) {
perror("Fork failed");
exit(1);
} else if (pid == 0) { // Child process
char *args[] = {"ls", "-la", NULL};
execvp("ls", args);
perror("execvp failed");
exit(1);
} else { // Parent process
wait(NULL);
cout << "Child process completed.\n";
}

return 0;
}
Experiment – 2: -
Aim: - I. Implementing CPU scheduling policies :-
(a) SJF
(b) Priority
(c) FCFS
(d) Multi-level queue

a) SJF:-
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Process {
int pid;
int burst_time;
int arrival_time;
};

bool compareArrivalTime(Process a, Process b) {


return a.arrival_time < b.arrival_time;
}
bool compareBurstTime(Process a, Process b) {
return a.burst_time < b.burst_time;
}

void SJF(vector<Process> processes) {


// Sort processes by arrival time
sort(processes.begin(), processes.end(), compareArrivalTime);

int time = 0, waiting_time = 0, turnaround_time = 0;

cout << "Gantt Chart:" << endl;

for (int i = 0; i < processes.size(); i++) {


// Print the process name and its execution time
cout << processes[i].pid << " ";

// Calculate waiting time and turnaround time


waiting_time += time - processes[i].arrival_time;
turnaround_time += time + processes[i].burst_time -
processes[i].arrival_time;

// Increment time
time += processes[i].burst_time;
}

cout << endl;


cout << "Average Waiting Time: " << (float)waiting_time / processes.size() <<
endl;
cout << "Average Turnaround Time: " << (float)turnaround_time /
processes.size() << endl;
}

int main() {
// ... (Code to generate processes randomly)

SJF(processes);

return 0;
}
b) Priority: -
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Process {
int pid;
int burst_time;
int arrival_time;
int priority;
};

bool compareArrivalTime(Process a, Process b) {


return a.arrival_time < b.arrival_time;
}

bool comparePriority(Process a, Process b) {


return a.priority < b.priority;
}

void PriorityScheduling(vector<Process> processes) {


// Sort processes by arrival time
sort(processes.begin(), processes.end(), compareArrivalTime);
int time = 0, waiting_time = 0, turnaround_time = 0;

cout << "Gantt Chart:" << endl;

while (!processes.empty()) {
// Find the process with the highest priority among the arrived processes
int highest_priority = INT_MAX;
int highest_priority_index = -1;
for (int i = 0; i < processes.size(); i++) {
if (processes[i].arrival_time <= time && processes[i].priority <
highest_priority) {
highest_priority = processes[i].priority;
highest_priority_index = i;
}
}

if (highest_priority_index 1 == -1) {
// No process has arrived yet
time++;
continue;
}

Process current_process = processes[highest_priority_index];


processes.erase(processes.begin() + highest_priority_index);

// Print the process name and its execution time


cout << current_process.pid << " ";
// Calculate waiting time and turnaround time
waiting_time += time - current_process.arrival_time;
turnaround_time += time + current_process.burst_time -
current_process.arrival_time;

// Increment time
time += current_process.burst_time;
}

cout << endl;


cout << "Average Waiting Time: " << (float)waiting_time / processes.size() <<
endl;
cout << "Average Turnaround Time: " << (float)turnaround_time /
processes.size() << endl;
}

int main() {
// ... (Code to generate processes randomly, including priority)

PriorityScheduling(processes);

return 0;
}
c) FCFS: -
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Process {
int pid;
int burst_time;
int arrival_time;
};

bool compareArrivalTime(Process a, Process b) {


return a.arrival_time < b.arrival_time;
}

void FCFS(vector<Process> processes) {


// Sort processes by arrival time
sort(processes.begin(), processes.end(), compareArrivalTime);

int time = 0, waiting_time = 0, turnaround_time = 0;

cout << "Gantt Chart:" << endl;

for (int i = 0; i < processes.size(); i++) {


// Print the process name and its execution time
cout << processes[i].pid << " ";

// Calculate waiting time and turnaround time


waiting_time += time - processes[i].arrival_time;
turnaround_time += time + processes[i].burst_time -
processes[i].arrival_time;

// Increment time
time += processes[i].burst_time;
}
cout << endl;
cout << "Average Waiting Time: " << (float)waiting_time / processes.size()
<< endl;
cout << "Average Turnaround Time: " << (float)turnaround_time /
processes.size() << endl;
}

int main() {
// ... (Code to generate processes randomly)

FCFS(processes);

return 0;
}

d) Multilevel: -
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

struct Process {
int pid;
int burst_time;
int arrival_time;
int priority;
};

// Function to simulate FCFS scheduling within a queue


void FCFS(queue<Process>& q, int& time) {
Process p = q.front();
q.pop();
time += p.burst_time;
cout << p.pid << " ";
}

// Function to simulate SJF scheduling within a queue


void SJF(queue<Process>& q, int& time) {
// Sort the queue by burst time
sort(q.begin(), q.end(), [](Process a, Process b) { return a.burst_time <
b.burst_time; });
Process p = q.front();
q.pop();
time += p.burst_time;
cout << p.pid << " ";
}

void MultiLevelQueue(vector<Process> processes) {


// Create multiple queues based on priority levels
queue<Process> queue1, queue2, queue3;

// Assign processes to queues based on priority


for (Process p : processes) {
if (p.priority == 1) {
queue1.push(p);
} else if (p.priority == 2) {
queue2.push(p);
} else {
queue3.push(p);
}
}

int time = 0;
cout << "Gantt Chart:" << endl;

while (!queue1.empty() || !queue2.empty() || !queue3.empty()) {


// Schedule from the highest priority queue
if (!queue1.empty()) {
FCFS(queue1, time); // Or SJF, Priority, etc.
} else if (!queue2.empty()) {
SJF(queue2, time); // Or FCFS, Priority, etc.
} else {
FCFS(queue3, time); // Or SJF, Priority, etc.
}
}

cout << endl;


// Calculate and print performance metrics (e.g., average waiting time,
turnaround time)
}

int main() {
// ... (Code to generate processes randomly, including priority)

MultiLevelQueue(processes);

return 0;
}
Experiment – 3: -
Aim: -
I. Implement file storage allocation techniques:
(a) Contiguous (using array)
(b) Linked –list (using linked list)
(c) Indirect allocation (indexing)

a) Contiguous Allocation
#include <iostream>
#include <vector>
using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
};

void contiguousAllocation(vector<Block>& blocks, int file_size) {


int bestFitIndex = -1;
int bestFitSize = INT_MAX;

// Find the best fit block


for (int i = 0; i < blocks.size(); ++i) {
if (blocks[i].is_free && blocks[i].size >= file_size) {
if (blocks[i].size < bestFitSize) {
bestFitIndex = i;
bestFitSize = blocks[i].size;
}
}
}

if (bestFitIndex != -1) {
// Allocate the block
blocks[bestFitIndex].is_free = false;
cout << "Allocated block " << bestFitIndex + 1 << " of size " <<
bestFitSize << " to the file." << endl;
} else {
cout << "Memory allocation failed. Not enough contiguous
free space." << endl;
}
}

int main() {
vector<Block> blocks = {
{1, 10, true},
{2, 5, true},
{3, 8, false},
{4, 12, true},
{5, 6, true}
};

int file_size = 7;

contiguousAllocation(blocks, file_size);

// Print the updated block status


for (const Block& block : blocks) {
cout << "Block " << block.block_id << ": " << (block.is_free ?
"Free" : "Allocated") << ", Size: " << block.size << endl;
}

return 0;
}
b)Linked Allocation
#include <iostream>

using namespace std;

struct Node {
int block_id;
int size;
bool is_free;
Node* next;
};

void linkedAllocation(Node*& head, int file_size) {


Node* current = head;
int total_allocated = 0;

while (current != nullptr && total_allocated < file_size) {


if (current->is_free && current->size >= file_size) {
// Allocate the block
current->is_free = false;
total_allocated += current->size;
cout << "Allocated block " << current->block_id << " of size "
<< current->size << " to the file." << endl;
return;
}
current = current->next;
}

cout << "Memory allocation failed. Not enough contiguous free


space." << endl;
}

int main() {
// Create a linked list of blocks
Node* head = new Node{1, 10, true, nullptr};
head->next = new Node{2, 5, true, nullptr};
head->next->next = new Node{3, 8, false, nullptr};
head->next->next->next = new Node{4, 12, true, nullptr};

int file_size = 7;

linkedAllocation(head, file_size);
// Print the updated linked list
Node* current = head;
while (current != nullptr) {
cout << "Block " << current->block_id << ": " << (current-
>is_free ? "Free" : "Allocated") << ", Size: " << current->size <<
endl;
current = current->next;
}

// Remember to deallocate the linked list to avoid memory leaks


// ... (code to deallocate the linked list)

return 0;
}
c)Indexed Allocation
#include <iostream>
#include <vector>

using namespace std;

struct Block {
int block_id;
bool is_free;
int file_id; // To identify the file it's allocated to
};
void indexedAllocation(vector<Block>& disk, int file_size, int
index_table_size, int file_id) {
int blocks_needed = (file_size + index_table_size - 1) /
index_table_size;

// Find contiguous free blocks


int start_block = -1;
for (int i = 0; i < disk.size(); i++) {
if (disk[i].is_free) {
if (start_block == -1) {
start_block = i;
}
if (i - start_block + 1 == blocks_needed) {
// Allocate contiguous blocks to the file
for (int j = start_block; j <= i; j++) {
disk[j].is_free = false;
disk[j].file_id = file_id; // Assign the file ID
}

// Update the index table (simple implementation)


int index = 0;
for (int j = start_block; j <= i; j++) {
// Assuming a simple index table as an array
// Replace this with a more suitable data structure if
needed
int index_entry = j;
// ... (Update the index table with index_entry)
}

return;
}
} else {
start_block = -1;
}
}

cout << "Memory allocation failed. Not enough contiguous free


space." << endl;
}

int main() {
const int DISK_SIZE = 10;
vector<Block> disk(DISK_SIZE);

// Initialize disk space


for (int i = 0; i < DISK_SIZE; i++) {
disk[i].block_id = i;
disk[i].is_free = true;
disk[i].file_id = -1;
}

int file_size = 7;
int index_table_size = 3;
int file_id = 1; // Assign a unique file ID

indexedAllocation(disk, file_size, index_table_size, file_id);

// Print the disk status


for (const Block& block : disk) {
cout << "Block " << block.block_id << ": " << (block.is_free ?
"Free" : "Allocated") << ", File ID: " << block.file_id << endl;
}

return 0;
}
Experiment – 4: -
Aim: -
Implementation of Contiguous allocation
techniques:
(a) Worst-Fit
(b) Best-Fit
(c) First-Fit

1. Worst-Fit Allocation
#include <iostream>
using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
};

void worstFit(Block blocks[], int n, int process_size) {


int worst_fit_idx = -1;
int worst_fit_size = 0;

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


if (blocks[i].is_free && blocks[i].size >= process_size) {
if (blocks[i].size > worst_fit_size) {
worst_fit_idx = i;
worst_fit_size = blocks[i].size;
}
}
}

if (worst_fit_idx != -1) {
// Allocate the block
blocks[worst_fit_idx].is_free = false;
cout << "Allocated block " << worst_fit_idx + 1 << " of size " <<
worst_fit_size << " to the process." << endl;
} else {
cout << "Memory allocation failed.\n";
}
}

int main() {
int n = 5;
Block blocks[n] = {{1, 100}, {2, 500}, {3, 200}, {4, 300}, {5, 600}};

int process_size = 210;

worstFit(blocks, n, process_size);

// Print the memory allocation status


for (int i = 0; i < n; i++) {
cout << "Block " << i + 1 << ": " << (blocks[i].is_free ? "Free" :
"Allocated") << endl;
}

return 0;
}
2. Best-Fit Allocation
#include <iostream>

using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
};

void bestFit(Block blocks[], int n, int process_size) {


int best_fit_idx = -1;
int best_fit_size = INT_MAX;

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


if (blocks[i].is_free && blocks[i].size >= process_size) {
if (blocks[i].size < best_fit_size) {
best_fit_idx = i;
best_fit_size = blocks[i].size;
}
}
}

if (best_fit_idx != -1) {
// Allocate the block
blocks[best_fit_idx].is_free = false;
cout << "Allocated block " << best_fit_idx + 1 << " of size " <<
best_fit_size << " to the process." << endl;
} else {
cout << "Memory allocation failed.\n";
}
}

int main() {
int n = 5;
Block blocks[n] = {{1, 100}, {2, 500}, {3, 200}, {4, 300}, {5, 600}};
int process_size = 210;

bestFit(blocks, n, process_size);

// Print the memory allocation status


for (int i = 0; i < n; i++) {
cout << "Block " << i + 1 << ": " << (blocks[i].is_free ? "Free" :
"Allocated") << endl;
}

return 0;
}
3. First-Fit Allocation
#include <iostream>

using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
};
void firstFit(Block blocks[], int n, int process_size) {
for (int i = 0; i < n; i++) {
if (blocks[i].is_free && blocks[i].size >= process_size) {
// Allocate the block
blocks[i].is_free = false;
cout << "Allocated block " << i + 1 << " of size " <<
blocks[i].size << " to the process." << endl;
return;
}
}

cout << "Memory allocation failed.\n";


}

int main() {
int n = 5;
Block blocks[n] = {{1, 100}, {2, 500}, {3, 200}, {4, 300}, {5, 600}};

int process_size = 210;

firstFit(blocks, n, process_size);

// Print the memory allocation status


for (int i = 0; i < n; i++) {
cout << "Block " << i + 1 << ": " << (blocks[i].is_free ? "Free" :
"Allocated") << endl;
}

return 0;
}
Experiment – 5: -
Aim:- Calculation of external and internal
fragmentation.
• External Fragmentation: Occurs when there is enough total
free memory to satisfy a request, but it is not contiguous.
• Internal Fragmentation: Occurs when a process is allocated
more memory than it actually needs.
Implementation in C++
C++
#include <iostream>
#include <vector>

using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
int allocated_to; // Process ID or file ID
};

void calculateFragmentation(vector<Block>& blocks, vector<int>


process_sizes) {
int external_fragmentation = 0, internal_fragmentation = 0;
for (Block block : blocks) {
if (block.is_free) {
external_fragmentation += block.size;
} else {
int wasted_space = block.size -
process_sizes[block.allocated_to - 1];
internal_fragmentation += wasted_space;
}
}

cout << "External Fragmentation: " << external_fragmentation <<


endl;
cout << "Internal Fragmentation: " << internal_fragmentation <<
endl;
}

// ... (Rest of the code for allocation algorithms)

int main() {
// ... (Initialize blocks and processes)

// Perform allocation (e.g., using first-fit, best-fit, or worst-fit)

// Calculate fragmentation
calculateFragmentation(blocks, process_sizes);

return 0;
}

Experiment 6:-
Aim: - Implementation of Compaction for the
continually changing memory layout and
calculate total movement of data.
#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

struct Block {
int block_id;
int size;
bool is_free;
int allocated_to; // Process ID or file ID
};

void compactMemory(vector<Block>& blocks) {


int hole_start = 0;
int current_block = 0;

while (current_block < blocks.size()) {


if (blocks[current_block].is_free) {
// Skip to the next allocated block
current_block++;
continue;
}

// Shift the current block to the hole


if (current_block != hole_start) {
// Calculate the amount of data to be moved
int data_size = sizeof(Block);

// Shift the block and update its position


memmove(&blocks[hole_start], &blocks[current_block],
data_size);
blocks[hole_start].block_id = hole_start;
// Update the free space of the previous block
blocks[current_block].is_free = true;
}

hole_start += blocks[hole_start].size;
current_block++;
}
}

int main() {
int n = 5;
vector<Block> blocks = {
{1, 100, false, 1},
{2, 50, true},
{3, 200, true},
{4, 300, false, 2},
{5, 600, true}
};

// Simulate memory allocation (you can implement your own


allocation strategy)
// ...

// Compact the memory


compactMemory(blocks);

// Print the memory status after compaction


for (const Block& block : blocks) {
cout << "Block " << block.block_id << ": " << (block.is_free ?
"Free" : "Allocated to Process " + to_string(block.allocated_to)) <<
endl;
}

return 0;
}
Experiment 7: -
Aim:- Implementation of resource allocation graph
(RAG).
#include <iostream>
#include <vector>

using namespace std;

struct Process {
int id;
vector<int> requested;
vector<int> allocated;
};

struct Resource {
int id;
int instances;
};

void createRAG(vector<Process>& processes, vector<Resource>&


resources, int n, int m) {
int graph[n + m][n + m];
// Initialize the graph with 0s
for (int i = 0; i < n + m; ++i) {
for (int j = 0; j < n + m; ++j) {
graph[i][j] = 0;
}
}

// Create edges for process to resource requests


for (int i = 0; i < n; ++i) {
for (int j = 0; j < processes[i].requested.size(); ++j) {
graph[i][n + processes[i].requested[j]] = 1;
}
}

// Create edges for resource to process allocations


for (int i = 0; i < n; ++i) {
for (int j = 0; j < processes[i].allocated.size(); ++j) {
graph[n + processes[i].allocated[j]][i] = 1;
}
}

// Print the adjacency matrix representation


for (int i = 0; i < n + m; ++i) {
for (int j = 0; j < n + m; ++j) {
cout << graph[i][j] << " ";
}
cout << endl;
}
}

int main() {
// ... (Input process and resource information)

createRAG(processes, resources, n, m);

return 0;
}
Experiment – 8: -
Aim: - Implementation of Banker’s Algorithm.
#include <iostream>

using namespace std;

bool isSafe(int processes, int resources, int available[], int


maxm[][resources], int alloc[][resources], int need[][resources]) {
int finish[processes] = {0};
int work[resources];

// Copy available resources to work


for (int i = 0; i < resources; i++) {
work[i] = available[i];
}

int count = 0;
while (count < processes) {
bool found = false;
for (int p = 0; p < processes; p++) {
if (finish[p] == 0) {
int j;
for (j = 0; j < resources; j++) {
if (need[p][j] > work[j]) {
break;
}
}
if (j == resources) {
for (int k = 0; k < resources; k++) {
work[k] += alloc[p][k];
}
finish[p] = 1;
found = true;
count++;
}
}
}

if (!found) {
return false; // System is in unsafe state
}
}

return true; // System is in safe state


}

int main() {
int processes, resources;
cout << "Enter the number of processes: ";
cin >> processes;
cout << "Enter the number of resources: ";
cin >> resources;

int available[resources], maxm[processes][resources],


alloc[processes][resources], need[processes][resources];

// Input available resources


cout << "Enter available resources: ";
for (int i = 0; i < resources; i++) {
cin >> available[i];
}

// Input maximum demand matrix


cout << "Enter maximum demand matrix:\n";
for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
cin >> maxm[i][j];
}
}

// Input allocation matrix


cout << "Enter allocation matrix:\n";
for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
cin >> alloc[i][j];
}
}

// Calculate need matrix


for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
need[i][j] = maxm[i][j] - alloc[i][j];
}
}

if (isSafe(processes, resources, available, maxm, alloc, need)) {


cout << "System is in a safe state.\n";
} else {
cout << "System is in an unsafe state.\n";
}

return 0;
}
Experiment – 9: -
Aim: - Conversion of resource allocation graph
(RAG) to wait-for-graph (WFG) for each
type of method used for storing graph.

#include <iostream>
#include <vector>

using namespace std;

struct Process {
int id;
vector<int> requested;
vector<int> allocated;
};

struct Resource {
int id;
int instances;
};

void createWaitForGraph(vector<Process>& processes,


vector<Resource>& resources, int n, int m) {
vector<vector<int>> wait_for_graph(n, vector<int>(n, 0));

// Identify waiting processes and create edges


for (int i = 0; i < n; ++i) {
for (int j = 0; j < processes[i].requested.size(); ++j) {
int resource_id = processes[i].requested[j];
for (int k = 0; k < n; ++k) {
if (k != i && processes[k].allocated[resource_id] > 0) {
wait_for_graph[i][k] = 1; // Process i is waiting for process
k
}
}
}
}

// Print the wait-for graph


cout << "Wait-for Graph:\n";
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << wait_for_graph[i][j] << " ";
}
cout << endl;
}
}

int main() {
// Input number of processes and resources
int n, m;
cout << "Enter the number of processes: ";
cin >> n;
cout << "Enter the number of resources: ";
cin >> m;

// Input process information


vector<Process> processes(n);
for (int i = 0; i < n; ++i) {
processes[i].id = i;
cout << "Enter the number of resources requested by process "
<< i + 1 << ": ";
int num_requested;
cin >> num_requested;
for (int j = 0; j < num_requested; ++j) {
int resource_id;
cout << "Enter resource ID: ";
cin >> resource_id;
processes[i].requested.push_back(resource_id);
}
cout << "Enter the number of resources allocated to process " <<
i + 1 << ": ";
int num_allocated;
cin >> num_allocated;
for (int j = 0; j < num_allocated; ++j) {
int resource_id;
cout << "Enter resource ID: ";
cin >> resource_id;
processes[i].allocated.push_back(resource_id);
}
}

// Input resource information (optional, if needed)


vector<Resource> resources(m);
for (int i = 0; i < m; ++i) {
resources[i].id = i;
cout << "Enter the number of instances for resource " << i + 1 <<
": ";
cin >> resources[i].instances;
}

createWaitForGraph(processes, resources, n, m);

return 0;
}
Experiment – 10:-
Aim: - Implement the solution for Bounded Buffer
(Producer-Consumer) problem using
inter process communication technique –
Semaphores.

i. #include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

class BoundedBuffer {
public:
BoundedBuffer(int size) : buffer_size(size), in(0), out(0), count(0)
{
buffer = new int[size];
}

void produce(int item) {


unique_lock<mutex> lock(mutex_);
while (count == buffer_size) {
not_full.wait(lock);
}
buffer[in] = item;
in = (in + 1) % buffer_size;
count++;
not_empty.notify_one();
}

int consume() {
unique_lock<mutex> lock(mutex_);
while (count == 0) {
not_empty.wait(lock);
}
int item = buffer[out];
out = (out + 1) % buffer_size;
count--;
not_full.notify_one();
return item;
}

private:
int *buffer;
int buffer_size;
int in, out, count;
mutex mutex_;
condition_variable not_full, not_empty;
};

// ... (Producer and Consumer threads)

ii. #include <iostream>


#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

class SharedResource {
public:
void read() {
unique_lock<mutex> lock(mutex_);
while (writer_count > 0) {
reader_count.wait(lock);
}
reader_count++;
lock.unlock();
// Read the shared resource
lock.lock();
reader_count--;
if (reader_count == 0) {
writer.notify_one();
}
lock.unlock();
}

void write() {
unique_lock<mutex> lock(mutex_);
while (reader_count > 0 || writer_count > 0) {
writer.wait(lock);
}
writer_count++;
// Write to the shared resource
writer_count--;
reader_count.notify_all();
writer.notify_one();
lock.unlock();
}

private:
mutex mutex_;
condition_variable reader_count, writer;
int reader_count = 0, writer_count = 0;
};

Experiment – 11: -
Aim: - FORK and JOIN construct

I. Average of Odd and Even Numbers


#include <iostream>
#include <vector>

using namespace std;

int main() {
int aadhar_number = 123456789012;
vector<int> digits;

while (aadhar_number > 0) {


digits.push_back(aadhar_number % 10);
aadhar_number /= 10;
}

int even_sum = 0, even_count = 0;


int odd_sum = 0, odd_count = 0;

for (int digit : digits) {


if (digit % 2 == 0) {
even_sum += digit;
even_count++;
} else {
odd_sum += digit;
odd_count++;
}
}

if (even_count > 0) {
double even_avg = static_cast<double>(even_sum) /
even_count;
cout << "Average of even digits: " << even_avg << endl;
} else {
cout << "No even digits found." << endl;
}

if (odd_count > 0) {
double odd_avg = static_cast<double>(odd_sum) /
odd_count;
cout << "Average of odd digits: " << odd_avg << endl;
} else {
cout << "No odd digits found." << endl;
}
return 0;
}

II. Additive Primes and Circular Primes


C++
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
using namespace std;

bool isPrime(int num) {


// ... (Implement prime number checking logic)
}

bool isCircularPrime(int num) {


// ... (Implement circular prime checking logic)
}

int main() {
vector<int> primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};

pid_t pid = fork();

if (pid < 0) {
perror("Fork failed");
exit(1);
} else if (pid == 0) { // Child process
// Find circular primes
for (int i = 0; i < primes.size(); i++) {
if (isCircularPrime(primes[i])) {
cout << primes[i] << " is a circular prime.\n";
}
}
exit(0);
} else { // Parent process
// Find additive primes
for (int i = 0; i < primes.size(); i++) {
for (int j = i + 1; j < primes.size(); j++) {
if (isPrime(primes[i] + primes[j])) {
cout << primes[i] << " + " << primes[j] << " = " <<
primes[i] + primes[j] << " is a prime.\n";
}
}
}
wait(NULL); // Wait for child process to finish
}

return 0;
}

You might also like