0% found this document useful (0 votes)
7 views6 pages

Module 4 C Programming

Notes

Uploaded by

gokuhello859
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)
7 views6 pages

Module 4 C Programming

Notes

Uploaded by

gokuhello859
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/ 6

Module 4

Problem Solving in C

Multithreading –

In C, the term "multithreading" describes the use of numerous threads concurrently. Each thread does a
different task. Due to the concurrent nature of multithreading, many tasks may be carried out at once.
OR
Multithreading allows a program to perform multiple tasks concurrently, improving performance on
multicore systems.

Thread-

A thread is the fundamental building block of any process's execution. A program is made up of several
processes, and each process is made up of threads, which are much more basic units.
OR
A lightweight process that shares the same memory space with other threads in the same process.

Life Cycle of a Thread-


1- New
2- Active
 Runnable
 Running
3- Block / Waiting
4- Terminate
 Normal Termination
 Abnormal Termination

New-
In this situation, a new process is generated.

Active – In this state a thread either get the CPU or waiting for the CPU.

Runnable- It is a state in which, a process is prepared and waiting for a processor to be assigned.
Running- It is the state in which, thread get the CPU (process is working).

Block/Waiting- When a process is in this state, something is waiting to happen.

Terminate- It is the state in which the procedure is being carried out.

Normal Termination- When procedure is completed successfully.


Abnormal Termination- When procedure is not completed and thread is stop forcefully in between.

How to Write C Programmes for Multithreading?


Although multithreading applications are not built-in to the C language, it is possible depending on the
operating system.
The pthread.h standard library is used to implement the multithreading idea in C.
However, there is currently no compiler that can do this. We must employ platform-specific
implementations, such as the "POSIX" threads library, by using the header file pthread.h.
POSIX threads (pthreads):

POSIX (Portable Operating System Interface): A standard for maintaining compatibility between
operating systems, ensuring portability of code across UNIX-like systems.

Multithreading Library: The pthread library provides functions to create, manage, and synchronize threads
in C programs.

Thread Creation: Use pthread_create() to create a new thread, which runs a specific function concurrently
with the main program.

Syntax:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void *), void *arg);

Thread Joining: Use pthread_join() to ensure the main program waits for a thread to finish before
continuing execution.

Mutex for Synchronization: Pthreads offer mutex locks (pthread_mutex_t) to ensure that shared resources
are accessed safely by multiple threads, preventing race conditions.

Condition Variables: Pthreads support condition variables (pthread_cond_t) to allow threads to wait for or
signal certain conditions before proceeding.

Portability: Since pthreads adhere to the POSIX standard, programs using pthreads are portable across
different UNIX-like systems, including Linux and macOS.

Efficiency: Multithreading can increase performance by taking advantage of multicore processors, allowing
tasks to be performed simultaneously.

What is a Race Condition in Multithreading?

A race condition occurs when two or more threads access shared data at the same time, and at least one of
them modifies it.
Because thread execution order is unpredictable, this can lead to incorrect or unexpected results.

What is Synchronization in Multithreading?

Synchronization means controlling the access of multiple threads to shared resources (like variables, files,
etc.) so that only one thread can use it at a time.

It helps prevent issues like:


 Race Condition.
 Data inconsistency
 Crashes

Types of Synchronization in C (POSIX Threads):

1- Using Mutex (Mutual Exclusion).


2- Using Semaphores.
3- Atomic Operations.
Using Mutex-

A Mutex (Mutual Exclusion) is a synchronization primitive used in multithreading to prevent multiple


threads from accessing shared resources at the same time.
It acts like a gatekeeper:
Only one thread can acquire the mutex and enter the critical section, while others must wait until the lock is
released.

Why Mutex is Needed in Multithreading:

In a multithreaded program, race conditions may occur if two or more threads access and modify shared data
simultaneously.
This can lead to unexpected behavior or corrupted data.
To avoid this, mutex locks are used to protect the critical section of the code — the part that accesses shared
resources.

Using Semaphores-

Semaphores are like counters that control access to resources.

OR

It control access to a limited number of resources


 sem_wait() → Wait/decrement
 sem_post() → Signal/increment

Atomic Operations:
It do fast, simple thread-safe operations.
 Use functions like __sync_fetch_and_add() or <stdatomic.h> .
 These are lock-free, faster but limited in features.

What is a System Call?

A system call is a request from a user-level program to the operating system's kernel to perform a task that
the program cannot do directly — like accessing hardware or system resources.
 System calls allow programs to interact with the OS.
 They are the bridge between your code and the operating system.
 Examples: read(), write(), fork(), exec().

Examples of system calls:

open(): Opens a file


read(): Reads data from a file
write(): Writes data to a file
close(): Closes a file
fork(): Creates a new process
exec(): Replaces process image
wait(): Waits for child process
exit(): Exits the program
getpid(): Gets current process ID
kill(): Sends signal to a process
Some Example with code:

Using write() System Call-

#include <unistd.h>
int main() {
const char *message = "Hello from system call!\n";
write(1, message, 24); // 1 = stdout, 24 = number of bytes
return 0;
}

Using read() System Call-

#include <stdio.h>
#include <fcntl.h> // For open()
#include <unistd.h> // For read(), close()

int main() {
int fd;
char buffer[100];

// Open the file (read-only mode)


fd = open("example.txt", O_RDONLY);

if (fd < 0) {
perror("Error opening file");
return 1;
}

// Read up to 100 bytes from the file


int bytesRead = read(fd, buffer, sizeof(buffer) - 1);

if (bytesRead < 0) {
perror("Error reading file");
close(fd);
return 1;
}

// Null-terminate and print the content


buffer[bytesRead] = '\0';
printf("File content:\n%s\n", buffer);

// Close the file


close(fd);

return 0;
}
Using fork() + execvp() Call –

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

#define MAX_INPUT 1024


#define MAX_ARGS 64

int main() {
char input[MAX_INPUT];
char *args[MAX_ARGS];

while (1) {
printf("mini-shell> ");
fflush(stdout);

// Read input
if (!fgets(input, MAX_INPUT, stdin)) {
break; // Handle Ctrl+D (EOF)
}

// Remove newline character


input[strcspn(input, "\n")] = 0;

// Exit command
if (strcmp(input, "exit") == 0) {
break;
}

// Parse input into arguments


int i = 0;
args[i] = strtok(input, " ");
while (args[i] != NULL && i < MAX_ARGS - 1) {
i++;
args[i] = strtok(NULL, " ");
}

args[i] = NULL; // Null-terminate the argument list

// Create child process


pid_t pid = fork();

if (pid < 0) {
perror("fork failed");
exit(1);
}

if (pid == 0) {
// Child process
execvp(args[0], args);
perror("exec failed"); // If exec fails
exit(1);
} else {
// Parent process
wait(NULL); // Wait for child to finish
}
}

printf("Exiting mini shell.\n");


return 0;
}

Inter-Process Communication:

IPC (Inter-Process Communication) is a mechanism that allows processes to communicate with each other
and synchronize their actions.
Since processes have separate memory spaces, they need IPC to:
 Share data
 Coordinate execution
 Avoid conflicts

Pipes:
A pipe is one of the simplest IPC mechanisms.
It provides a unidirectional communication channel between processes.

OR

Pipes are one of the simplest forms of IPC, especially used between a parent and its child process.

Characteristics of a Pipe:

Feature Description

Direction One-way (data flows in one direction)


Used between Related processes (e.g., parent-child)
Temporary Exists only while the processes are running
Buffered Kernel manages the buffer

Benefits of Using Pipes:

 Simple and fast for basic communication


 Good for parent-child communication
 No need for temporary files

You might also like