Contents

Multithreading and Parallelism

Multithreading, Concurrency, and Parallelism in Computing

1. What is Multithreading?

  • Multithreading: The ability of a CPU (or a single process) to manage multiple threads of execution concurrently.
  • Threads share process resources (memory, file descriptors), but each has its own execution context (registers, stack).
  • Used for responsiveness, task separation, and efficient CPU use.

1.1 Example Usage:

  • A GUI application runs its interface in one thread and background tasks (e.g., downloads) in another.
  • Servers use worker threads to handle multiple client connections.

1.2 C Example: Simple Thread Creation (POSIX pthreads)

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

void* worker(void* arg) {
    int n = *(int*)arg;
    printf("Worker thread running with n = %d\n", n);
    sleep(1);
    printf("Worker thread done\n");
    return NULL;
}

int main() {
    pthread_t tid;
    int n = 42;
    pthread_create(&tid, NULL, worker, &n);
    printf("Main thread continues\n");
    pthread_join(tid, NULL); // Wait for worker to finish
    printf("Main thread exits\n");
    return 0;
}
Main thread continues
Worker thread running with n = 42
Worker thread done
Main thread exits

2. What is Concurrency?

  • Concurrency: Managing multiple tasks at once, but not necessarily simultaneously.
  • Achieved via interleaved execution (context switching), often on a single-core CPU.
  • Focuses on structure and coordination of tasks, not their simultaneous execution.

2.1 Example Usage:

  • Handling multiple client requests in a web server by switching between them rapidly.
  • Producer-consumer problems, where producer and consumer share a buffer.

2.2 C Example: Producer-Consumer with Mutex and Condition Variable

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

#define BUF_SIZE 5
int buffer[BUF_SIZE], count = 0;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER, not_empty = PTHREAD_COND_INITIALIZER;

void* producer(void* _) {
    for (int i = 0; i < 10; ++i) {
        pthread_mutex_lock(&mtx);
        while (count == BUF_SIZE) pthread_cond_wait(&not_full, &mtx);
        buffer[count++] = i;
        printf("Produced %d\n", i);
        pthread_cond_signal(&not_empty);
        pthread_mutex_unlock(&mtx);
        usleep(100000);
    }
    return NULL;
}

void* consumer(void* _) {
    for (int i = 0; i < 10; ++i) {
        pthread_mutex_lock(&mtx);
        while (count == 0) pthread_cond_wait(&not_empty, &mtx);
        int val = buffer[--count];
        printf("Consumed %d\n", val);
        pthread_cond_signal(&not_full);
        pthread_mutex_unlock(&mtx);
        usleep(150000);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    return 0;
}
Produced 0
Consumed 0
Produced 1
Consumed 1
Produced 2
Consumed 2
Produced 3
Produced 4
Consumed 4
Produced 5
Consumed 5
Produced 6
Produced 7
Consumed 7
Produced 8
Consumed 8
Produced 9
Consumed 9
Consumed 6
Consumed 3

3. What is Parallelism?

  • Parallelism: Performing multiple computations simultaneously on different processors or cores.
  • Requires multi-core CPUs, multiple processors, or hardware acceleration.
  • Focuses on actual simultaneous execution for faster completion.

3.1 Example Usage:

  • Scientific simulations dividing work among CPU cores.
  • Multimedia processing: one core decodes video, another processes audio.

3.2 C Example: Parallel Array Sum Using Threads

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

#define N 1000000
#define THREADS 4
int array[N];
long long partial_sum[THREADS];

void* sum_array(void* arg) {
    int idx = *(int*)arg;
    int chunk = N / THREADS;
    int start = idx * chunk;
    int end = (idx == THREADS-1) ? N : start + chunk;
    long long sum = 0;
    for (int i = start; i < end; ++i) sum += array[i];
    partial_sum[idx] = sum;
    return NULL;
}

int main() {
    for (int i = 0; i < N; ++i) array[i] = 1; // Fill with 1s
    pthread_t tids[THREADS];
    int ids[THREADS];
    for (int i = 0; i < THREADS; ++i) {
        ids[i] = i;
        pthread_create(&tids[i], NULL, sum_array, &ids[i]);
    }
    long long total = 0;
    for (int i = 0; i < THREADS; ++i) {
        pthread_join(tids[i], NULL);
        total += partial_sum[i];
    }
    printf("Total sum: %lld\n", total);
    return 0;
}
Total sum: 1000000

4. Concurrency vs Parallelism vs Multithreading

AspectConcurrencyParallelismMultithreading
Key FocusTask structure/coordinationSimultaneous executionMultiple threads per process
HardwareNot required (can be 1 CPU)Requires >1 CPU/coreSupported by most OS/CPUs
ExampleProducer-consumer, async IOMatrix multiply on 8 coresGUI thread + worker threads
Code ExampleMutexes, semaphoresThread pools, OpenMPpthreads, Java threads

5. Practical Uses and Issues

  • Responsiveness (GUIs, games): main thread for UI, workers for background.
  • Servers: Handle many clients using thread pools.
  • Scientific/financial: Distribute heavy computation across cores (parallelism).
  • Challenges: race conditions, deadlocks, false sharing, thread contention, debugging complexity.

6. Tools, Libraries, and Extensions

  • POSIX threads (pthreads): Standard in C for Linux/Unix.
  • OpenMP: High-level API for parallel loops.
  • std::thread (C++11+), Java threads.
  • Thread sanitizer, Helgrind, Valgrind for debugging.