Multithreading with POSIX Threads
Concurrency — C-র চূড়ান্ত সীমা
1. Thread vs Process
- Thread একই memory space share করে; process করে না।
- Thread তৈরি ও context-switch সস্তা।
- একই প্রোগ্রামের একাধিক CPU core ব্যবহারের উপায়।
2. Hello, Thread
#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
#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;
}
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);
if নয়, while ব্যবহার করুন।
5. Deadlock, Livelock, Starvation
- Deadlock: দুটি thread দুটি lock ধরে একে অপরের lock-এর জন্য অপেক্ষা করে।
- Livelock: Thread-গুলো state বদলায়, কিন্তু progress হয় না।
- Starvation: কোনো thread-ই কখনো schedule পায় না।
Rule: একাধিক lock নিলে সবসময় একই global order-এ নিন।
6. Practice Problems
- Spawn 4 threads; each prints its id.৪টি thread তৈরি।
✨ Show Answer
Section 2 reference।
- Parallel sum of an array with 4 threads.৪ thread-এ parallel sum।
✨ Show Answer
Array-কে 4 ভাগ করুন; প্রতিটি thread নিজের ভাগের sum local variable-এ; main-এ merge। কোনো lock লাগে না (disjoint ranges)।
- 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।
- 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।
- 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।
- Dining philosophers — solve without deadlock.Dining philosophers।
✨ Show Answer
সমাধান: fork-গুলোকে ordered numbering; প্রতিটি philosopher lower-numbered fork আগে নিক। Circular wait ভাঙ্গলে deadlock নেই।
- 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); - Barrier synchronization.Barrier।
✨ Show Answer
pthread_barrier_init(&b, NULL, N);; প্রতিটি thread কাজ শেষেpthread_barrier_wait(&b);— সব N-টি thread না পৌঁছানো পর্যন্ত অপেক্ষা। - 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 এখনও দরকার।
- 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। - 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 লাগে না।
- 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 হলে কম।
- 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 ছাপিয়ে যায়।
- 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 দিয়েও।
- 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 (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
| Thread | An 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_create | Spawns a new thread. | নতুন thread তৈরি। |
pthread_join | Wait for a thread to finish. | Thread শেষ হওয়ার অপেক্ষা। |
| Concurrency | Multiple tasks making progress within overlapping time. | একই সময়ে একাধিক task চলা। |
| Parallelism | Tasks literally running at the same instant on multiple cores. | একাধিক core-এ একসাথে চলা। |
| Race Condition | Outcome depends on unpredictable thread scheduling. | Thread schedule-এর উপর ফল নির্ভর। |
| Critical Section | Code that must run atomically (one thread at a time). | একসাথে এক thread-ই চালাতে পারে এমন কোড। |
| Mutex | Mutual-exclusion lock for protecting a critical section. | Critical section রক্ষাকারী lock। |
| Condition Variable | Lets a thread wait for a state change. | State বদল হলে thread জাগানোর সুবিধা। |
| Semaphore | Counter-based synchronization primitive. | Counter-ভিত্তিক sync primitive। |
| Deadlock | Two threads each waiting for the other's lock — frozen forever. | দুই thread পরস্পরের lock-এর অপেক্ষায় আটকে। |
| Atomic Operation | Operation guaranteed indivisible. | একসাথে সম্পন্ন হওয়া operation। |
| Memory Model | Rules about visibility/order of memory operations across threads. | Thread-জুড়ে memory operation-এর visibility-এর নিয়ম। |
| ThreadSanitizer | Runtime 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।