Chapter 4 Exercises
Remember Process vs Threads
● A child process is a separate, independent
process created by a parent. It has its own
Process ID (PID), PCB, and resources, and it’s
placed in the process queue. If the parent
process terminates, the child process may or may
not be affected.
● A thread, on the other hand, is a smaller unit
within a process that shares the same memory and
resources. If the parent process dies, all its
threads die as well.
Remember Process vs Threads
Analogy:
● A process is like a house — it has its own
foundation, wiring, and address. Different houses
can only communicate through formal methods (like
IPC).
● A thread is like a room within the same house —
it shares everything (plumbing, wiring, and
address) with other rooms. Communication is easy,
but if the house collapses, all rooms are lost
too.
Threads
● Threads are lightweight units of execution within a process.
● They allow a program to perform multiple tasks
concurrently, improving efficiency and responsiveness.
● 💡 Example: Just like you can listen to music while writing
code, threads let your program do several things at once.
Process Thread
Definition An independent program in A segment (or lightweight unit) of a
execution process
Weight Heavyweight Lightweight
Creation Time more time less time
Termination Time more time less time
Communication Slower and requires inter-process Faster as they share the same
communication (IPC) mechanisms memory space
Context Switching Slower Faster
Resource Usage More resources (separate memory Fewer resources
and system resources)
Scheduling by OS Each process is treated as a All the level peer threads are
separate task by the OS treated as a single task by OS
Memory Sharing have separate memory spaces Share the same memory and
resources (like data and code)
Dependency Independent of each other Dependent on their parent process.
Process vs Thread
Process: A complete program in execution with its own
memory space
Thread: A subset of a process that shares the same
memory space with other threads
Difference: Multiple threads = shared resources,
Multiple processes = isolated resources
Process vs Thread
Thread
● Has its own stack.
● Did not create a copy of the PCB
in memory.
● Data access is within the same
process itself.
Process
● A copy of the program itself executes.
● The new process can not modify data
stored in the parent process.
Process vs Thread in Memory
<pthread.h>
● In C language, POSIX <pthread.h> standard API
(Application program Interface) for all thread related
functions.
● It allows us to create multiple threads for concurrent
process flows.
<pthread.h>
Function Description Usage Return Value
pthread_create() Creates a new thread int pthread_create( pthread_t *thread, const
and starts execution. pthread_attr_t *attr, void*(*start_routine)(void *),
void *arg);
Takes a function pointer
● thread: The ID of the thread to wait for. This must be a
that will be executed in thread created by pthread_create().
the new thread.
● attr: Pointer to a thread attributes object that sets options
like stack size, scheduling policy, etc. You can pass NULL to Return Value
use default attributes.
● Returns 0 on success.
● start_routine: Pointer to the function that the thread will
execute. This function must take a single void * argument
● Returns a nonzero
and return a void * result.
error code (e.g.,
● arg: A pointer to the argument you want to pass to the EINVAL, EAGAIN) on
thread function. Use NULL if no argument is needed. failure.
pthread_join() Waits for the specified pthread_join(pthread_t thread, void **retval);
thread to terminate. It
● thread: The ID of the thread to wait for. This must be a
blocks the calling thread thread created by pthread_create().
until the target thread
finishes. ● retval: A pointer to a pointer that will store the value
returned by the thread’s start function (return value). If
you don’t care about the return value, pass NULL.
4.1 Pthread_create
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// Function that will be executed by the thread generic pointer type — a special kind
of pointer that can hold the address of
any data type.
void* print_message(void* msg) {
char *string = (char*) msg;
printf("%s\n", string);
return NULL;
} data type defined in the POSIX
int main() { Threads (pthreads) library, used to
uniquely identify a thread.
pthread_t thread1, thread2; // Declare two thread identifiers
const char* message1 = "Hello from thread 1!";
const char* message2 = "Hello from thread 2!";
// Create two threads
pthread_create(&thread1, NULL, print_message, message1);
pthread_create(&thread2, NULL, print_message, message2);
// Wait for the threads to finish
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Hello from the Main Thread\n") ;
return 0;
}
4.2 Passing Struct data to a thread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define a struct to hold data
typedef struct {
int id;
char message[50];
} thread_data_t;
void *thread_function(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
printf("Thread ID: %d, Message: %s\n", data->id, data->message);
return NULL;
}
int main() {
pthread_t thread;
thread_data_t data = {1,"Hello from the thread!"} ;
pthread_create(&thread, NULL, thread_function, (void *)&data) ;
pthread_join(thread, NULL);
return 0;
}
4.3 Passing Pointer to a local variable
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *thread_function(void *arg) {
int *id = (int *)arg;
printf("Thread received ID: %d\n", *id);
return NULL;
}
Wrong Output!!!
int main() {
pthread_t threads[10];
for (int i = 0; i < 10; i++) {
int data = i; // Local variable reused for each thread
pthread_create(&threads[i], NULL, thread_function, &data) ;
}
for (int i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
4.3 Passing Pointer to a local variable
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *thread_function(void *arg) {
int *id = (int *)arg;
printf("Thread received ID: %d\n", *id);
free(id) ; // free allocated memory
return NULL;
Correct Version
}
int main() {
pthread_t threads[10];
for (int i = 0; i < 10; i++) {
int *data = malloc(sizeof(int));// allocate memory for ID
*data = i;
pthread_create(&threads[i], NULL, thread_function, data) ;
}
for (int i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
4.4 Return Value from Thread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> // Thread function to sum a segment of prime
#define NUM_THREADS 2 numbers
int primes[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; void* thread_function(void* arg) {
thread_data_t* data = (thread_data_t*)arg;
typedef struct { // Cast the argument to the correct type
int start_index; int start = data->start_index;
int count; int count = data->count;
} thread_data_t; int sum = 0;
for (int i = 0; i < count; i++) {
int main() { sum += primes[start + i];
pthread_t threads[NUM_THREADS]; }
thread_data_t thread_data[NUM_THREADS]; // dynamic allocation for the answer and
int i; return the pointer to the main_thread
int *result ; int* result = malloc(sizeof(int));
int global_sum = 0; *result = sum;
// Create threads to sum segments of the prime array // If we returned a pointer to a local
for (i = 0; i < NUM_THREADS; i++) { variable
thread_data[i].start_index = i * 5; // Starting index for each thread (0 and 5) // int *result = &sum ;
thread_data[i].count = 5; // Each thread sums 5 numbers return result;
pthread_create(&threads[i], NULL, thread_function,&thread_data[i]); }
}
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], (void**)&result);
global_sum += *result;
free(result); // Free the allocated memory for the result
}
printf("Global Sum is %d\n", global_sum);
return 0;
}
4.5 Global vs. Local Variables in Threads
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int global_counter = 0; // Global variable shared by all threads
void *thread_function(void *arg) {
int local_counter = 0; // Local variable unique to each thread
int * data = (int*) arg ;
global_counter++;
local_counter++;
printf("Thread %d - Global: %d, Local: %d\n", *data, global_counter, local_counter); // What is the output of this line
free(data);
return NULL;
}
int main() {
pthread_t threads[2];
for (int i = 0; i < 2; i++) {
int* data = malloc(sizeof(int));
*data = i;
pthread_create(&threads[i], NULL, thread_function, data);
}
for (int i = 0; i < 2; i++) {
pthread_join(threads[i], NULL);
}
printf("Final Global Counter: %d\n", global_counter); // What is the output of this line
return 0;
}