0% found this document useful (1 vote)
52 views24 pages

Linux Commands and System Monitoring Guide

The document is a student guide for the Operating Systems Lab 2024, detailing various experiments involving Linux commands and system calls. It covers basic commands like 'ps', 'strace', and 'gdb', as well as experiments related to process management, memory usage, and program execution. Each section includes explanations, commands, and expected outputs for practical understanding.

Uploaded by

adithskumar32
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 (1 vote)
52 views24 pages

Linux Commands and System Monitoring Guide

The document is a student guide for the Operating Systems Lab 2024, detailing various experiments involving Linux commands and system calls. It covers basic commands like 'ps', 'strace', and 'gdb', as well as experiments related to process management, memory usage, and program execution. Each section includes explanations, commands, and expected outputs for practical understanding.

Uploaded by

adithskumar32
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

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

OPERATING SYSTEMS LAB 2024 SCHEME- STUDENT GUIDE


Staff: [Link] Beevi A ,RIT Kottayam
================================================================================

================================================================================
EXPERIMENT 1: BASIC LINUX COMMANDS
================================================================================

--------------------------------------------------------------------------------
1.1 ps - Process Status
--------------------------------------------------------------------------------
EXPLANATION: Shows currently running processes with their Process IDs (PIDs).
Displays process information like CPU usage, memory usage, and command name.

COMMAND:
ps

OUTPUT:
PID TTY TIME CMD
1234 pts/0 00:00:00 bash
5678 pts/0 00:00:00 ps

COMMAND:
ps aux

OUTPUT:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 169416 11234 ? Ss 10:00 0:02 /sbin/init
student 1234 0.0 0.2 21234 8456 pts/0 Ss 10:15 0:00 bash
--------------------------------------------------------------------------------
1.2 strace - Trace System Calls
--------------------------------------------------------------------------------
EXPLANATION: Tracks and displays all system calls made by a program during
execution. Useful for debugging and understanding how programs interact with
the operating system.

COMMAND:
strace ls

OUTPUT:
execve("/bin/ls", ["ls"], 0x7ffd... = 0
brk(NULL) = 0x55a8...
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
getdents64(3, /* 10 entries */, 32768) = 320
write(1, "[Link] file2.c folder1\n", 28) = 28
--------------------------------------------------------------------------------
1.3 gdb - GNU Debugger
--------------------------------------------------------------------------------
EXPLANATION: Allows step-by-step execution of programs to find bugs and errors.
You can set breakpoints, inspect variables, and control program execution.

COMMAND:
gcc -g program.c -o program
gdb ./program

GDB COMMANDS:
(gdb) break main
(gdb) run
(gdb) next
(gdb) print variable_name
(gdb) quit
--------------------------------------------------------------------------------
1.4 strings - Display Printable Strings
--------------------------------------------------------------------------------
EXPLANATION: Extracts and displays all readable text from binary files. Useful
for finding hardcoded strings, error messages, or file paths in executables.

COMMAND:
strings /bin/ls

OUTPUT:
/lib64/[Link].2
[Link].6
__cxa_finalize
strcmp
printf
...
--------------------------------------------------------------------------------
1.5 objdump - Display Object File Information
--------------------------------------------------------------------------------
EXPLANATION: Shows detailed information about compiled object files including
assembly code and symbols. Helps understand how code is compiled into machine
instructions.

COMMAND:
objdump -d program

OUTPUT:
program: file format elf64-x86-64

Disassembly of section .text:

0000000000001149 <main>:
1149: 55 push %rbp
114a: 48 89 e5 mov %rsp,%rbp
114d: b8 00 00 00 00 mov $0x0,%eax
--------------------------------------------------------------------------------
1.6 nm - List Symbols
--------------------------------------------------------------------------------
EXPLANATION: Lists all symbols (function names, variable names) in an object
file or executable. Shows which functions are defined and which are external.

COMMAND:
nm program

OUTPUT:
0000000000001149 T main
U printf@@GLIBC_2.2.5
0000000000004010 D __data_start
--------------------------------------------------------------------------------
1.7 file - Determine File Type
--------------------------------------------------------------------------------
EXPLANATION: Identifies the type of a file by examining its contents, not just
the extension. Works for executables, text files, images, etc.

COMMAND:
file program

OUTPUT:
program: ELF 64-bit LSB executable, x86-64, dynamically linked

COMMAND:
file [Link]

OUTPUT:
[Link]: ASCII text
--------------------------------------------------------------------------------
1.8 od - Octal Dump
--------------------------------------------------------------------------------
EXPLANATION: Displays file contents in octal, hexadecimal, or other formats.
Useful for viewing binary files or non-printable characters in text files.

COMMAND:
echo "Hello" > [Link]
od -c [Link]

OUTPUT:
0000000 H e l l o \n
0000006

COMMAND:
od -x [Link]

OUTPUT:
0000000 6548 6c6c 0a6f
0000006
--------------------------------------------------------------------------------
1.9 xxd - Hexadecimal Dump
--------------------------------------------------------------------------------
EXPLANATION: Displays file contents in hexadecimal format along with ASCII
representation. More readable than od for viewing binary data.
COMMAND:
xxd [Link]

OUTPUT:
00000000: 4865 6c6c 6f0a Hello.
--------------------------------------------------------------------------------
1.10 time - Measure Execution Time
--------------------------------------------------------------------------------
EXPLANATION: Measures how long a command takes to execute. Shows real time
(wall clock), user time (CPU in user mode), and system time (CPU in kernel mode).

COMMAND:
time ls

OUTPUT:
[Link] file2.c folder1

real 0m0.002s
user 0m0.001s
sys 0m0.001s
--------------------------------------------------------------------------------
1.11 fuser - Identify Process Using File
--------------------------------------------------------------------------------
EXPLANATION: Shows which processes are currently using a specific file. Helpful
when you can't delete a file because it's in use.

COMMAND:
fuser /home/student/[Link]

OUTPUT:
/home/student/[Link]: 1234

COMMAND:
fuser -v /home/student/[Link]

OUTPUT:
USER PID ACCESS COMMAND
/home/student/[Link]: student 1234 f.... vim
--------------------------------------------------------------------------------
1.12 top - Display Running Processes
--------------------------------------------------------------------------------
EXPLANATION: Shows real-time view of running processes with CPU and memory usage.
Updates continuously and can be used to monitor system performance.

COMMAND:
top

OUTPUT:
top - 10:30:45 up 5 days, 2:15, 2 users, load average: 0.52, 0.58, 0.59
Tasks: 234 total, 1 running, 233 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.3 us, 1.2 sy, 0.0 ni, 96.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7864.0 total, 2341.5 free, 3234.6 used, 2287.9 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4234.5 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND


1234 student 20 0 234567 12345 8901 S 5.0 0.2 0:12.34 firefox

================================================================================
EXPERIMENT 2: USE /proc FILE SYSTEM
================================================================================

--------------------------------------------------------------------------------
(a) Number of CPU Cores
--------------------------------------------------------------------------------
EXPLANATION: Counts how many processor cores your computer has. Each core can
run separate tasks simultaneously.

COMMAND:
cat /proc/cpuinfo | grep processor | wc -l

OUTPUT:
4

ALTERNATIVE COMMAND:
nproc

OUTPUT:
4
--------------------------------------------------------------------------------
(b) Total Memory and Free Memory
--------------------------------------------------------------------------------
EXPLANATION: Shows total RAM installed and how much is currently free.
MemAvailable is the best indicator of memory available for starting new
applications.

COMMAND:
cat /proc/meminfo | grep MemTotal
cat /proc/meminfo | grep MemFree
cat /proc/meminfo | grep MemAvailable

OUTPUT:
MemTotal: 8052748 kB
MemFree: 2341567 kB
MemAvailable: 5234890 kB

ALTERNATIVE COMMAND:
free -h

OUTPUT:
total used free shared buff/cache available
Mem: 7.7Gi 3.1Gi 2.2Gi 145Mi 2.2Gi 5.0Gi
Swap: 2.0Gi 0B 2.0Gi

--------------------------------------------------------------------------------
(c) Number of Processes Currently Running
--------------------------------------------------------------------------------
EXPLANATION: Counts all processes that are currently active in the system. Each
running program creates one or more processes.

COMMAND:
ps aux | wc -l

OUTPUT:
235

ALTERNATIVE COMMAND:
ls /proc | grep "^[0-9]" | wc -l

OUTPUT:
234
--------------------------------------------------------------------------------
(d) Processes in Running and Blocked States
--------------------------------------------------------------------------------
EXPLANATION: Shows how many processes are actively running on CPU and how many
are blocked waiting for I/O operations. Blocked processes are waiting for disk,
network, or other resources.

COMMAND:
cat /proc/stat | grep procs

OUTPUT:
procs_running 2
procs_blocked 0

ALTERNATIVE USING ps:


ps aux | grep " R " | wc -l (Running)
ps aux | grep " D " | wc -l (Blocked/Disk sleep)

OUTPUT:
2
0
--------------------------------------------------------------------------------
(e) Number of Processes Forked Since Boot
--------------------------------------------------------------------------------
EXPLANATION: Shows total number of processes created since system started. This
is much higher than current processes because most processes start, do their
work, and then exit.

COMMAND:
cat /proc/stat | grep processes
OUTPUT:
processes 45678

COMPARISON: This number (45678) is much larger than current running processes
(234) because:
- Many processes start and finish during system runtime
- This is cumulative count since boot
- Current processes = only those alive now
--------------------------------------------------------------------------------
(f) Context Switches for a Process
--------------------------------------------------------------------------------
EXPLANATION: Shows how many times a process was switched in/out of CPU.
Voluntary switches happen when process waits for resources; involuntary
switches happen when time slice expires.

COMMAND (For specific PID, example: PID 1234):


cat /proc/1234/status | grep ctxt

OUTPUT:
voluntary_ctxt_switches: 1234
nonvoluntary_ctxt_switches: 567

ALTERNATIVE:
grep ctxt /proc/1234/status

================================================================================
EXPERIMENT 3: PRINT SYSTEM TIME AND ANALYZE CPU USAGE
================================================================================

EXPLANATION: This experiment creates a program that prints time, then uses /proc
to measure how long it ran in user mode (executing your code) and kernel mode
(executing system calls).
--------------------------------------------------------------------------------
Step 1: Create the Program
--------------------------------------------------------------------------------

COMMAND:
nano timeprint.c

PROGRAM CODE:

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

int main() {
time_t current_time;
char* time_string;

current_time = time(NULL);
time_string = ctime(&current_time);
printf("Current system time: %s", time_string);
printf("Process ID: %d\n", getpid());

// Do some work
for(int i = 0; i < 1000000; i++) {
int x = i * i;
}

return 0;
}
--------------------------------------------------------------------------------
Step 2: Compile and Run
--------------------------------------------------------------------------------

COMMAND:
gcc timeprint.c -o timeprint
./timeprint

OUTPUT:
Current system time: Sat Dec 13 10:30:45 2025
Process ID: 5678
--------------------------------------------------------------------------------
Step 3: Check CPU Times Using /proc
--------------------------------------------------------------------------------

METHOD 1 - Get the PID first, then check:

COMMAND:
./timeprint &
PID=$!
cat /proc/$PID/stat

OUTPUT (fields 14 and 15 show user and kernel time):


5678 (timeprint) R 1234 5678 1234 ... 14 2 ...

Better way - see specific fields:

COMMAND:
./timeprint &
PID=$!
awk '{print "User time: " $14 "\nKernel time: " $15}' /proc/$PID/stat

OUTPUT:
User time: 14
Kernel time: 2

METHOD 2 - Using time command (easier):

COMMAND:
time ./timeprint
OUTPUT:
Current system time: Sat Dec 13 10:30:45 2025
Process ID: 5678

real 0m0.012s
user 0m0.008s
sys 0m0.004s
================================================================================
EXPERIMENT 4: FORK SYSTEM CALL AND PROCESS TREE
================================================================================

EXPLANATION: This experiment demonstrates how fork() creates a new child process.
The parent and child are separate processes with different PIDs, and we can
visualize their relationship using pstree.
--------------------------------------------------------------------------------
Step 1: Create Fork Program
--------------------------------------------------------------------------------

COMMAND:
nano fork_demo.c

PROGRAM CODE:

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

int main() {
pid_t pid;
printf("Before fork - PID: %d\n", getpid());
pid = fork();

if (pid < 0) {
printf("Fork failed!\n");
return 1;
}
else if (pid == 0) {
// Child process
printf("CHILD Process - PID: %d, Parent PID: %d\n",
getpid(), getppid());
sleep(30); // Keep process alive to see in pstree
}
else {
// Parent process
printf("PARENT Process - PID: %d, Child PID: %d\n",
getpid(), pid);
sleep(30); // Keep process alive to see in pstree
}

return 0;
}
--------------------------------------------------------------------------------
Step 2: Compile and Run
--------------------------------------------------------------------------------
COMMAND:
gcc fork_demo.c -o fork_demo
./fork_demo

OUTPUT:
Before fork - PID: 6789
PARENT Process - PID: 6789, Child PID: 6790
CHILD Process - PID: 6790, Parent PID: 6789
--------------------------------------------------------------------------------
Step 3: View Process Tree
--------------------------------------------------------------------------------
In another terminal while program is running:

COMMAND:
pstree -p 6790

OUTPUT:
systemd(1)───bash(1234)───fork_demo(6789)───fork_demo(6790)

Show with PID numbers:

COMMAND:
pstree -p | grep fork_demo

OUTPUT:
├─bash(1234)───fork_demo(6789)─┬─fork_demo(6790)

More detailed view:

COMMAND:
ps -ef | grep fork_demo

OUTPUT:
student 6789 1234 0 10:30 pts/0 00:00:00 ./fork_demo
student 6790 6789 0 10:30 pts/0 00:00:00 ./fork_demo

Show full tree from init:

COMMAND:
pstree -p 1 | grep -A 5 -B 5 fork_demo

OUTPUT:
systemd(1)─┬─systemd(456)───(sd-pam)(457)
├─cron(234)
├─bash(1234)───fork_demo(6789)───fork_demo(6790)
├─other processes..
================================================================================
================================================================================
QUESTION 5: Process Creation and Program Execution
=========================================================================
OBJECTIVE:
Create two programs - one to add integers and another to demonstrate
fork() and execvp() system calls for process creation and program
execution.

PART A: Addition Program (myadder)


-------------------------------------------------------------------------
File: myadder.c

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

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


if (argc != 3) {
printf("Usage: %s <num1> <num2>\n", argv[0]);
return 1;
}

int num1 = atoi(argv[1]);


int num2 = atoi(argv[2]);
int sum = num1 + num2;

printf("Sum of %d and %d = %d\n", num1, num2, sum);

return 0;
}

COMPILATION:
$ gcc myadder.c -o myadder

TESTING myadder:
$ ./myadder 10 20
Sum of 10 and 20 = 30

-------------------------------------------------------------------------

PART B: Fork and Exec Program


-------------------------------------------------------------------------
File: fork_exec.c

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

int main() {
pid_t pid;
int num1, num2;

printf("Enter two integers to add: ");


scanf("%d %d", &num1, &num2);

// Create a new process


pid = fork();

if (pid < 0) {
// Fork failed
fprintf(stderr, "Fork failed\n");
return 1;
}
else if (pid == 0) {
// Child process
printf("\nChild Process (PID: %d)\n", getpid());
printf("Executing myadder program...\n\n");

// Convert integers to strings for execvp


char num1_str[20], num2_str[20];
sprintf(num1_str, "%d", num1);
sprintf(num2_str, "%d", num2);

// Prepare arguments for execvp


char *args[] = {"./myadder", num1_str, num2_str, NULL};

// Replace child process image with myadder


execvp(args[0], args);

// If execvp returns, it means it failed


fprintf(stderr, "Execvp failed\n");
return 1;
}
else {
// Parent process
printf("\nParent Process (PID: %d)\n", getpid());
printf("Created child process with PID: %d\n", pid);
printf("Waiting for child to complete...\n");

// Wait for child process to complete


wait(NULL);

printf("\nParent: Child process completed\n");


}

return 0;
}

COMPILATION:
$ gcc fork_exec.c -o fork_exec

EXECUTION:
$ ./fork_exec

SAMPLE OUTPUT:
-------------------------------------------------------------------------
Enter two integers to add: 15 25

Parent Process (PID: 1234)


Created child process with PID: 1235
Waiting for child to complete...

Child Process (PID: 1235)


Executing myadder program...
Sum of 15 and 25 = 40

Parent: Child process completed


-------------------------------------------------------------------------

=========================================================================
QUESTION 6: Parent-Child Process Synchronization
=========================================================================

OBJECTIVE:
Create a program where child prints "PCCSL407" and parent prints
"Operating Systems Lab". Use wait() to ensure correct output order.

PROGRAM:
-------------------------------------------------------------------------
File: parent_child_sync.c

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

int main() {
pid_t pid;

// Create a new process


pid = fork();

if (pid < 0) {
// Fork failed
fprintf(stderr, "Fork failed\n");
return 1;
}
else if (pid == 0) {
// Child process
printf("PCCSL407 ");
fflush(stdout); // Ensure output is printed immediately
}
else {
// Parent process
// Wait for child to complete first
wait(NULL);

// Now print parent's message


printf("Operating Systems Lab\n");
}

return 0;
}

COMPILATION:
$ gcc parent_child_sync.c -o parent_child_sync

EXECUTION:
$ ./parent_child_sync
SAMPLE OUTPUT:
-------------------------------------------------------------------------
PCCSL407 Operating Systems Lab
-------------------------------------------------------------------------

EXPLANATION:
The wait() system call in parent ensures that:
1. Child process executes first and prints "PCCSL407"
2. Parent waits for child to complete
3. Then parent prints "Operating Systems Lab"
4. Result: Sequential output in correct order

=========================================================================
QUESTION 7: Inter-Process Communication (IPC)
=========================================================================
PART A: Communication Using PIPE
-------------------------------------------------------------------------
OBJECTIVE:
Evaluate the expression: sqrt(b² - 4*a*c) using two processes
communicating via pipe. First process calculates b², second calculates
4*a*c, and first process computes final result.

File: ipc_pipe.c

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

int main() {
int pipe_fd[2];
pid_t pid;
double a, b, c;

printf("Enter values for a, b, c: ");


scanf("%lf %lf %lf", &a, &b, &c);

// Create pipe
if (pipe(pipe_fd) == -1) {
fprintf(stderr, "Pipe failed\n");
return 1;
}

pid = fork();

if (pid < 0) {
fprintf(stderr, "Fork failed\n");
return 1;
}
else if (pid == 0) {
// Child process: Calculate 4*a*c
close(pipe_fd[0]); // Close reading end

double result = 4 * a * c;
printf("Child: Calculated 4*a*c = %.2f\n", result);

// Write result to pipe


write(pipe_fd[1], &result, sizeof(double));
close(pipe_fd[1]);

exit(0);
}
else {
// Parent process: Calculate b² and final result
close(pipe_fd[1]); // Close writing end

double b_square = b * b;
printf("Parent: Calculated b² = %.2f\n", b_square);

// Read 4*a*c from child


double four_ac;
read(pipe_fd[0], &four_ac, sizeof(double));
close(pipe_fd[0]);

wait(NULL); // Wait for child to complete

// Calculate final result


double discriminant = b_square - four_ac;

printf("\nDiscriminant (b² - 4*a*c) = %.2f\n", discriminant);

if (discriminant >= 0) {
double final_result = sqrt(discriminant);
printf("Square root of discriminant = %.2f\n", final_result);
} else {
printf("Discriminant is negative. Square root is
imaginary.\n");
}
}

return 0;
}

COMPILATION:
$ gcc ipc_pipe.c -o ipc_pipe -lm

EXECUTION:
$ ./ipc_pipe

SAMPLE OUTPUT 1:
-------------------------------------------------------------------------
Enter values for a, b, c: 1 5 6
Child: Calculated 4*a*c = 24.00
Parent: Calculated b² = 25.00

Discriminant (b² - 4*a*c) = 1.00


Square root of discriminant = 1.00
-------------------------------------------------------------------------

SAMPLE OUTPUT 2:
-------------------------------------------------------------------------
Enter values for a, b, c: 2 4 1
Child: Calculated 4*a*c = 8.00
Parent: Calculated b² = 16.00

Discriminant (b² - 4*a*c) = 8.00


Square root of discriminant = 2.83
-------------------------------------------------------------------------
PART B: Communication Using MESSAGE QUEUE
-------------------------------------------------------------------------
OBJECTIVE:
First process sends a string to second process via message queue. Second
process reverses it and sends back. First process checks if palindrome.

File: ipc_msgqueue.c

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

#define MAX_TEXT 100

// Message structure
struct message {
long msg_type;
char msg_text[MAX_TEXT];
};

// Function to reverse a string


void reverse_string(char *str) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - 1 - i];
str[len - 1 - i] = temp;
}
}

int main() {
key_t key;
int msgid;
pid_t pid;
struct message msg;
char input_string[MAX_TEXT];

// Generate unique key


key = ftok(".", 'B');

// Create message queue


msgid = msgget(key, 0666 | IPC_CREAT);
if (msgid == -1) {
perror("msgget failed");
return 1;
}
pid = fork();

if (pid < 0) {
fprintf(stderr, "Fork failed\n");
return 1;
}
else if (pid == 0) {
// Child process: Receive, reverse, and send back

// Receive message from parent


msgrcv(msgid, &msg, sizeof(msg.msg_text), 1, 0);
printf("Child: Received string: %s\n", msg.msg_text);

// Reverse the string


reverse_string(msg.msg_text);
printf("Child: Reversed string: %s\n", msg.msg_text);

// Send reversed string back to parent


msg.msg_type = 2;
msgsnd(msgid, &msg, sizeof(msg.msg_text), 0);

exit(0);
}
else {
// Parent process: Send string and check palindrome

printf("Enter a string: ");


fgets(input_string, MAX_TEXT, stdin);
input_string[strcspn(input_string, "\n")] = 0; // Remove newline

// Send string to child


msg.msg_type = 1;
strcpy(msg.msg_text, input_string);
msgsnd(msgid, &msg, sizeof(msg.msg_text), 0);
printf("Parent: Sent string: %s\n", input_string);

// Receive reversed string from child


msgrcv(msgid, &msg, sizeof(msg.msg_text), 2, 0);
printf("Parent: Received reversed string: %s\n", msg.msg_text);

wait(NULL); // Wait for child to complete

// Check if palindrome
if (strcmp(input_string, msg.msg_text) == 0) {
printf("\nResult: The string IS a palindrome!\n");
} else {
printf("\nResult: The string is NOT a palindrome.\n");
}

// Remove message queue


msgctl(msgid, IPC_RMID, NULL);
}

return 0;
}

COMPILATION:
$ gcc ipc_msgqueue.c -o ipc_msgqueue
EXECUTION:
$ ./ipc_msgqueue

SAMPLE OUTPUT 1:
-------------------------------------------------------------------------
Enter a string: radar
Parent: Sent string: radar
Child: Received string: radar
Child: Reversed string: radar
Parent: Received reversed string: radar

Result: The string IS a palindrome!


-------------------------------------------------------------------------
SAMPLE OUTPUT 2:
-------------------------------------------------------------------------
Enter a string: hello
Parent: Sent string: hello
Child: Received string: hello
Child: Reversed string: olleh
Parent: Received reversed string: olleh

Result: The string is NOT a palindrome.


-------------------------------------------------------------------------
PART C: Communication Using SHARED MEMORY
-------------------------------------------------------------------------
OBJECTIVE:
First process sends three strings to second process via shared memory.
Second concatenates them and sends back. First process flips the case and
displays.

File: ipc_sharedmem.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <ctype.h>

#define SHM_SIZE 1024

// Function to flip case of string


void flip_case(char *str) {
for (int i = 0; str[i] != '\0'; i++) {
if (isupper(str[i])) {
str[i] = tolower(str[i]);
} else if (islower(str[i])) {
str[i] = toupper(str[i]);
}
}
}

int main() {
key_t key;
int shmid;
char *shared_memory;
pid_t pid;

char str1[100], str2[100], str3[100];

// Generate unique key


key = ftok(".", 'C');

// Create shared memory segment


shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
return 1;
}

// Attach shared memory


shared_memory = (char *)shmat(shmid, NULL, 0);
if (shared_memory == (char *)-1) {
perror("shmat failed");
return 1;
}

pid = fork();

if (pid < 0) {
fprintf(stderr, "Fork failed\n");
return 1;
}
else if (pid == 0) {
// Child process: Read, concatenate, and write back

sleep(1); // Wait for parent to write

// Read three strings from shared memory


char *ptr = shared_memory;
strcpy(str1, ptr);
ptr += strlen(str1) + 1;
strcpy(str2, ptr);
ptr += strlen(str2) + 1;
strcpy(str3, ptr);

printf("Child: Received strings: '%s', '%s', '%s'\n", str1, str2,


str3);

// Concatenate strings
char concatenated[SHM_SIZE];
sprintf(concatenated, "%s %s %s", str1, str2, str3);
printf("Child: Concatenated string: '%s'\n", concatenated);

// Write back to shared memory


strcpy(shared_memory, concatenated);

// Detach shared memory


shmdt(shared_memory);

exit(0);
}
else {
// Parent process: Write three strings

printf("Enter first string: ");


fgets(str1, 100, stdin);
str1[strcspn(str1, "\n")] = 0;

printf("Enter second string: ");


fgets(str2, 100, stdin);
str2[strcspn(str2, "\n")] = 0;

printf("Enter third string: ");


fgets(str3, 100, stdin);
str3[strcspn(str3, "\n")] = 0;

// Write three strings to shared memory


char *ptr = shared_memory;
strcpy(ptr, str1);
ptr += strlen(str1) + 1;
strcpy(ptr, str2);
ptr += strlen(str2) + 1;
strcpy(ptr, str3);

printf("Parent: Sent three strings to child\n\n");

wait(NULL); // Wait for child to complete

// Read concatenated string


char result[SHM_SIZE];
strcpy(result, shared_memory);
printf("\nParent: Received concatenated string: '%s'\n", result);

// Flip case
flip_case(result);
printf("Parent: After flipping case: '%s'\n", result);

// Detach and remove shared memory


shmdt(shared_memory);
shmctl(shmid, IPC_RMID, NULL);
}

return 0;
}

COMPILATION:
$ gcc ipc_sharedmem.c -o ipc_sharedmem

EXECUTION:
$ ./ipc_sharedmem

SAMPLE OUTPUT:
-------------------------------------------------------------------------
-------
Enter first string: Hello
Enter second string: S4
Enter third string: Students
Parent: Sent three strings to child
Child: Received strings: 'Hello', 'S4', 'Students'
Child: Concatenated string: 'Hello S4 Students'

Parent: Received concatenated string: 'Hello S4 Students'


Parent: After flipping case: 'hELLO s4 sTUDENTS'
-------------------------------------------------------------------------

=========================================================================
QUESTION 8: Multithreaded Statistical Calculator
=========================================================================

OBJECTIVE:
Write a multithreaded program that calculates mean, median, and standard
deviation for a list of integers using three separate worker threads.
- Multithreading with pthread
- Thread creation and joining
- Global variable sharing
- Statistical calculations (mean, median, standard deviation)
- Mathematical library usage

PROGRAM:
-------------------------------------------------------------------------
File: stats_calculator.c

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

// Global variables to store results


double mean_value = 0.0;
double median_value = 0.0;
double std_dev_value = 0.0;

// Global array to store integers


int *numbers;
int count;

// Comparison function for qsort


int compare(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}

// Thread function to calculate mean


void *calculate_mean(void *arg) {
long sum = 0;
for (int i = 0; i < count; i++) {
sum += numbers[i];
}
mean_value = (double)sum / count;
printf("Thread 1: Calculated Mean = %.2f\n", mean_value);
pthread_exit(0);
}

// Thread function to calculate median


void *calculate_median(void *arg) {
// Create a copy of the array for sorting
int *sorted = (int *)malloc(count * sizeof(int));
for (int i = 0; i < count; i++) {
sorted[i] = numbers[i];
}

// Sort the array


qsort(sorted, count, sizeof(int), compare);

// Calculate median
if (count % 2 == 0) {
median_value = (sorted[count/2 - 1] + sorted[count/2]) / 2.0;
} else {
median_value = sorted[count/2];
}

printf("Thread 2: Calculated Median = %.2f\n", median_value);

free(sorted);
pthread_exit(0);
}

// Thread function to calculate standard deviation


void *calculate_std_dev(void *arg) {
// Wait a bit to ensure mean is calculated first
pthread_t *mean_thread = (pthread_t *)arg;
pthread_join(*mean_thread, NULL);

double sum_squared_diff = 0.0;


for (int i = 0; i < count; i++) {
double diff = numbers[i] - mean_value;
sum_squared_diff += diff * diff;
}
std_dev_value = sqrt(sum_squared_diff / count);
printf("Thread 3: Calculated Standard Deviation = %.2f\n",
std_dev_value);
pthread_exit(0);
}

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


if (argc < 2) {
printf("Usage: %s <number1> <number2> ... <numberN>\n", argv[0]);
return 1;
}

// Get count of numbers


count = argc - 1;

// Allocate memory for numbers array


numbers = (int *)malloc(count * sizeof(int));

// Read numbers from command line


printf("Input numbers: ");
for (int i = 0; i < count; i++) {
numbers[i] = atoi(argv[i + 1]);
printf("%d ", numbers[i]);
}
printf("\n\n");
// Create threads
pthread_t mean_thread, median_thread, std_dev_thread;

printf("Creating worker threads...\n\n");

// Create mean thread


pthread_create(&mean_thread, NULL, calculate_mean, NULL);

// Create median thread


pthread_create(&median_thread, NULL, calculate_median, NULL);

// Create std_dev thread (pass mean_thread so it can wait)


pthread_create(&std_dev_thread, NULL, calculate_std_dev,
&mean_thread);

// Wait for median thread to complete


pthread_join(median_thread, NULL);

// Wait for std_dev thread to complete (mean_thread already joined


inside)
pthread_join(std_dev_thread, NULL);

// Display results
printf("\n========================================\n");
printf(" STATISTICAL ANALYSIS RESULTS\n");
printf("========================================\n");
printf("Mean: %.2f\n", mean_value);
printf("Median: %.2f\n", median_value);
printf("Standard Deviation: %.2f\n", std_dev_value);
printf("========================================\n");

// Free allocated memory


free(numbers);

return 0;
}

COMPILATION:
$ gcc stats_calculator.c -o stats_calculator -pthread -lm

EXECUTION:
$ ./stats_calculator 10 20 30 40 50

SAMPLE OUTPUT 1:
-------------------------------------------------------------------------
Input numbers: 10 20 30 40 50

Creating worker threads...

Thread 1: Calculated Mean = 30.00


Thread 2: Calculated Median = 30.00
Thread 3: Calculated Standard Deviation = 14.14

========================================
STATISTICAL ANALYSIS RESULTS
========================================
Mean: 30.00
Median: 30.00
Standard Deviation: 14.14
========================================
-------------------------------------------------------------------------
SAMPLE OUTPUT 2:
$ ./stats_calculator 5 15 25 35 45 55

Input numbers: 5 15 25 35 45 55

Creating worker threads...

Thread 1: Calculated Mean = 30.00


Thread 2: Calculated Median = 30.00
Thread 3: Calculated Standard Deviation = 17.08

========================================
STATISTICAL ANALYSIS RESULTS
========================================
Mean: 30.00
Median: 30.00
Standard Deviation: 17.08
========================================

You might also like