Multithreading with POSIX Threads

Concurrency — C-র চূড়ান্ত সীমা

~55 min Advanced 15 practice problems Live code

1. Thread vs Process

  • Thread একই memory space share করে; process করে না।
  • Thread তৈরি ও context-switch সস্তা।
  • একই প্রোগ্রামের একাধিক CPU core ব্যবহারের উপায়।

2. Hello, Thread

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

void *worker(void *arg) {
    long id = (long)arg;
    printf("hi from thread %ld\n", id);
    return NULL;
}

int main(void) {
    pthread_t t[4];
    for (long i = 0; i < 4; i++)
        pthread_create(&t[i], NULL, worker, (void *)i);
    for (int i = 0; i < 4; i++) pthread_join(t[i], NULL);
    return 0;
}
// Compile: gcc program.c -pthread

3. Race Conditions & Mutex

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

static long counter = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *inc(void *arg) {
    (void)arg;
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&lock);
        counter++;
        pthread_mutex_unlock(&lock);
    }
    return NULL;
}

int main(void) {
    pthread_t t[4];
    for (int i = 0; i < 4; i++) pthread_create(&t[i], NULL, inc, NULL);
    for (int i = 0; i < 4; i++) pthread_join(t[i], NULL);
    printf("counter = %ld (expected 400000)\n", counter);
    return 0;
}
Mutex ছাড়া counter++ atomic নয় — দুটি thread একই মান পড়ে, increment করে, একই মান write করে। Mutex নিশ্চিত করে একবারে একজনই critical section-এ প্রবেশ করে।

4. Condition Variables — Producer/Consumer

pthread_cond_t  cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t m  = PTHREAD_MUTEX_INITIALIZER;
int ready = 0;

// consumer
pthread_mutex_lock(&m);
while (!ready) pthread_cond_wait(&cv, &m);
// ... consume ...
pthread_mutex_unlock(&m);

// producer
pthread_mutex_lock(&m);
ready = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&m);
Always wait in a while loop Spurious wakeup হতে পারে — তাই if নয়, while ব্যবহার করুন।

5. Deadlock, Livelock, Starvation

  • Deadlock: দুটি thread দুটি lock ধরে একে অপরের lock-এর জন্য অপেক্ষা করে।
  • Livelock: Thread-গুলো state বদলায়, কিন্তু progress হয় না।
  • Starvation: কোনো thread-ই কখনো schedule পায় না।

Rule: একাধিক lock নিলে সবসময় একই global order-এ নিন।

6. Practice Problems

  1. Spawn 4 threads; each prints its id.
    ৪টি thread তৈরি।
    ✨ Show Answer

    Section 2 reference।

  2. Parallel sum of an array with 4 threads.
    ৪ thread-এ parallel sum।
    ✨ Show Answer

    Array-কে 4 ভাগ করুন; প্রতিটি thread নিজের ভাগের sum local variable-এ; main-এ merge। কোনো lock লাগে না (disjoint ranges)।

  3. Reproduce a race condition; fix with mutex; measure slowdown.
    Race condition, mutex দিয়ে fix, slowdown measure।
    ✨ Show Answer

    Section 3-এ mutex আছে। mutex removed version চালিয়ে দেখুন — expected-এর চেয়ে কম value আসে। Mutex যুক্ত করলে correct কিন্তু ~5-10× slower।

  4. Bounded buffer producer/consumer with mutex + condvar.
    Bounded buffer।
    ✨ Show Answer

    Queue (circular array) + size counter। Producer: full হলে cond_wait; কাজ করে cond_signal। Consumer: empty হলে cond_wait; কাজ করে cond_signal।

  5. Thread pool with fixed workers and a task queue.
    Thread pool।
    ✨ Show Answer

    Workers = N threads; queue-এ task (function pointer + arg)। Worker loop: queue empty হলে cond_wait; কাজ pop+execute; shutdown signal-এ exit।

  6. Dining philosophers — solve without deadlock.
    Dining philosophers।
    ✨ Show Answer

    সমাধান: fork-গুলোকে ordered numbering; প্রতিটি philosopher lower-numbered fork আগে নিক। Circular wait ভাঙ্গলে deadlock নেই।

  7. Readers-writers lock using pthread_rwlock.
    Reader-writer lock।
    ✨ Show Answer
    pthread_rwlock_t rw;
    pthread_rwlock_rdlock(&rw);   // readers share
    pthread_rwlock_wrlock(&rw);   // writers exclusive
    pthread_rwlock_unlock(&rw);
  8. Barrier synchronization.
    Barrier।
    ✨ Show Answer

    pthread_barrier_init(&b, NULL, N);; প্রতিটি thread কাজ শেষে pthread_barrier_wait(&b); — সব N-টি thread না পৌঁছানো পর্যন্ত অপেক্ষা।

  9. Use atomic ints (stdatomic.h) instead of mutex. Compare.
    Atomic vs mutex।
    ✨ Show Answer
    #include <stdatomic.h>
    _Atomic long counter = 0;
    atomic_fetch_add(&counter, 1);

    Simple counter-এ atomic অনেক দ্রুত (lock-এর overhead নেই)। Complex critical section-এ mutex এখনও দরকার।

  10. Deliberately cause a deadlock; detect with helgrind.
    Deadlock + helgrind detect।
    ✨ Show Answer

    Two threads, দুটি mutex বিপরীত order-এ lock করুক। Run: valgrind --tool=helgrind ./a.out — deadlock বা ordering violation report।

  11. Thread-local storage with __thread / thread_local.
    Thread-local storage।
    ✨ Show Answer
    __thread int tls_val;          // GCC extension
    // or:
    #include <threads.h>
    thread_local int tls_val;       // C11

    প্রতিটি thread-এর নিজস্ব copy — কোনো sync লাগে না।

  12. Benchmark single-threaded vs multi-threaded matrix multiply.
    Matrix multiply benchmark।
    ✨ Show Answer

    N thread-এ rows ভাগ করে distribute করুন। N = core count-এ সাধারণত N × speedup; memory-bandwidth-bound হলে কম।

  13. Why is lock contention sometimes worse than no parallelism?
    Lock contention-এ single thread-এর চেয়ে slow হয় কেন?
    ✨ Show Answer

    Lock acquire/release নিজেই overhead; এর উপর cache-line bouncing (একই memory একাধিক core-এ invalidate হয়)। Work-per-lock খুব ছোট হলে overhead ছাপিয়ে যায়।

  14. Amdahl's law — reason about max speedup from N cores.
    Amdahl's law।
    ✨ Show Answer

    Speedup = 1 / (s + p/N), যেখানে s = serial fraction, p = parallel fraction। N → ∞ হলেও max speedup = 1/s। 5% serial হলে max speedup 20× — infinite core দিয়েও।

  15. Read "The Little Book of Semaphores"; 1-paragraph summary.
    Little Book of Semaphores summary।
    ✨ Show Answer

    Free online book (Allen Downey) — semaphore, mutex, condvar-এর classical সমস্যা (dining philosophers, bounded buffer, reader-writer, barbers) ও patterns। Concurrency-র সবচেয়ে readable intro।

Glossary (শব্দকোষ)

TermMeaningবাংলায়
ThreadAn independent flow of execution sharing process memory.Process-এর memory ভাগাভাগি করা একটি execution flow।
POSIX Threads (pthreads)Standard threading API on Unix-like systems.Unix-এ standard threading API।
pthread_createSpawns a new thread.নতুন thread তৈরি।
pthread_joinWait for a thread to finish.Thread শেষ হওয়ার অপেক্ষা।
ConcurrencyMultiple tasks making progress within overlapping time.একই সময়ে একাধিক task চলা।
ParallelismTasks literally running at the same instant on multiple cores.একাধিক core-এ একসাথে চলা।
Race ConditionOutcome depends on unpredictable thread scheduling.Thread schedule-এর উপর ফল নির্ভর।
Critical SectionCode that must run atomically (one thread at a time).একসাথে এক thread-ই চালাতে পারে এমন কোড।
MutexMutual-exclusion lock for protecting a critical section.Critical section রক্ষাকারী lock।
Condition VariableLets a thread wait for a state change.State বদল হলে thread জাগানোর সুবিধা।
SemaphoreCounter-based synchronization primitive.Counter-ভিত্তিক sync primitive।
DeadlockTwo threads each waiting for the other's lock — frozen forever.দুই thread পরস্পরের lock-এর অপেক্ষায় আটকে।
Atomic OperationOperation guaranteed indivisible.একসাথে সম্পন্ন হওয়া operation।
Memory ModelRules about visibility/order of memory operations across threads.Thread-জুড়ে memory operation-এর visibility-এর নিয়ম।
ThreadSanitizerRuntime detector for data races.Data race ধরার runtime tool।

Summary — Module 38

Thread shared memory → power + risk। Mutex exclusion, condvar coordination। Deadlock এড়াতে consistent lock order। Simple counter-এ atomic। ThreadSanitizer দিয়ে test।

Next Module → Network Programming — TCP Sockets।