Skip to main content
Ajay Dhangar
EditReport

Thread Creation

A thread is an independent flow of execution within a process. Multiple threads within the same process share its resources (such as memory space, file descriptors, and global variables), allowing different tasks to execute concurrently and efficiently.


1. Introduction​

In C, threads are managed using the POSIX Threads (Pthreads) library (pthread.h). Multi-threading is essential when a program needs to execute multiple operations simultaneously, such as running background computations, handling concurrent network requests, or processing heavy I/O operations without freezing the main application.

The following example demonstrates concurrent execution by launching three independent mathematical worker threads alongside the main thread:

  • Thread 1: Generates rows of Pascal's Triangle
  • Thread 2: Computes Triangular Numbers
  • Thread 3: Generates Fibonacci Numbers

2. C Implementation​

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

// Thread 1: Generates and prints Pascal's Triangle rows
void *pascal_rows(void *arg) {
int n = *(int*)arg;
int a[50] = {0};
a[0] = 1;

for (int i = 0; i < n; i++) {
printf("Pascal row %d = ", i + 1);
// Compute the row backwards to update in place safely
for (int j = i; j > 0; j--) {
a[j] = a[j] + a[j - 1];
}

for (int j = 0; j <= i; j++) {
printf("%d ", a[j]);
}
printf("\n");
sleep(1);
}
pthread_exit(NULL);
}

// Thread 2: Computes and prints Triangular Numbers
void *triangular_nos(void *arg) {
int n = *(int*)arg;
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
printf("Triangular number %d = %d\n", i, sum);
sleep(2);
}
pthread_exit(NULL);
}

// Helper function for Fibonacci calculation
int fibonacci(int m) {
if (m <= 0) return 0;
if (m == 1) return 1;
return fibonacci(m - 1) + fibonacci(m - 2);
}

// Thread 3: Computes and prints Fibonacci Numbers
void *prt_fib(void *arg) {
int n = *(int*)arg;
for (int i = 1; i <= n; i++) {
printf("Fibonacci no %d = %d\n", i, fibonacci(i));
sleep(3);
}
pthread_exit(NULL);
}

int main() {
pthread_t p, t, f;
int x = 0;

printf("Enter a positive integer: ");
if (scanf("%d", &x) != 1 || x <= 0) {
printf("Invalid input.\n");
return 1;
}

// Creating threads concurrently
pthread_create(&p, NULL, pascal_rows, &x);
pthread_create(&t, NULL, triangular_nos, &x);
pthread_create(&f, NULL, prt_fib, &x);

// Waiting for threads to finish execution
pthread_join(p, NULL);
pthread_join(t, NULL);
pthread_join(f, NULL);

printf("End of main thread\n");
return 0;
}

Sample Input & Output​

Input:

Enter a positive integer: 3

Output (Interleaved due to concurrency):

Pascal row 1 = 1 
Triangular number 1 = 1
Fibonacci no 1 = 1
Pascal row 2 = 1 1
Triangular number 2 = 3
Pascal row 3 = 1 2 1
Fibonacci no 2 = 1
Triangular number 3 = 6
Fibonacci no 3 = 2
End of main thread

3. Deep Dive: How It Works​

3.1 Header Files​

  • <stdio.h> – Standard I/O operations (printf, scanf).
  • <pthread.h> – Provides Pthreads core functions, types, and macros.
  • <unistd.h> – System call wrapper interface providing the sleep() function.

3.2 Thread Creation API​

The main function initializes three threads via pthread_create().

Function Syntax​

int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg
);
ParameterTypePurpose
threadpthread_t *Pointer to a variable that stores the unique thread ID.
attrconst pthread_attr_t *Thread attributes (passing NULL applies default configuration like joinable state).
start_routinevoid *(*)(void *)Pointer to the function that the thread will execute.
argvoid *Pointer to the argument passed to the target function.

Note: Once pthread_create is invoked, execution shifts to a scheduled context switch where the target function runs asynchronously alongside the caller.

3.3 Argument Passing & Type Casting​

Because pthread_create requires a generic void * pointer for its arguments, data must be safely cast inside the thread functions:

  1. Passing: The address of the variable is passed: &x
  2. Receiving: The void *arg is cast back to its true type pointer and dereferenced:
int n = *(int*)arg;

3.4 Synchronization and Termination​

  • pthread_exit(NULL): Explicitly terminates the calling thread. Using this ensures that only the local execution stream wraps up, keeping other running peer threads alive.
  • pthread_join(thread_id, retval): Acts as a blocking synchronization barrier. The main thread pauses execution at each pthread_join line, waiting for the designated thread to finish before proceeding. This prevents the process from completing prematurely and creating zombie threads.

4. Execution Flow Summary​

The diagram below illustrates how the main thread spawns the worker threads, blocks until they are completely finished, and then finalizes the process:

Finished reading? Mark this topic as complete.