πŸ’₯ Let’s dissect [[asymmetric_pthreads/05_join_vs_detach_threads]] like a FAANG-grade concurrency surgeon β€” line by line, struct by struct, mutex by mutex.


🧬 File Dissection: [[05_join_vs_detach_threads]]


πŸ”Ή #define THREAD_COUNT 10

  • πŸ“Œ Spawns 10 threads total

  • βš–οΈ Half are detached, half are joinable

  • πŸ“Š Even indexes β†’ detached, odd β†’ joinable


πŸ”Ή pthread_mutex_t print_mutex

  • Used in safe_print()

  • Ensures logs don’t interleave mid-line

πŸ’‘ Without this, two threads calling printf may garble stdout


πŸ”Ή void safe_print(const char *fmt, ...)

pthread_mutex_lock(&print_mutex);
vprintf(fmt, args);
pthread_mutex_unlock(&print_mutex);
  • βœ… Thread-safe printing

  • πŸ”’ Uses va_list + vprintf() with lock wrapping

  • πŸ“Ž Reusable pattern in multi-threaded apps


πŸ”Ή char logs[MAX_LOGS][STR_BUFFER];

  • ⛓️ Global log buffer

  • Logs up to MAX_LOGS strings (256 chars each)


πŸ”Ή int log_index + pthread_mutex_t log_mutex

  • 🧠 Guards the current index into the log array

  • Prevents threads from overwriting each other’s logs

  • βœ… Classic use-case for a shared resource lock


πŸ”Ή shared_counter (⚠️ unprotected)

  • ❗️Not mutex-protected β†’ race condition

  • Multiple threads read, modify, write shared_counter at once:

temp = shared_counter;
temp += 1;
usleep(100);  // makes race more likely
shared_counter = temp;
  • πŸ’₯ This is intentional: to show data races in practice

πŸ”Ή typedef struct s_thread_args

typedef struct s_thread_args
{
	int	index;
	int	delay;
	int	should_detach;
}	t_thread_args;
  • βœ… Compact thread argument struct

  • πŸ§ͺ Each thread gets:

    • index: thread ID (0–9)

    • delay: seconds to sleep()

    • should_detach: whether to pthread_detach or not


πŸ” Lifecycle: worker()

Thread X started
-> logs PID + TID
-> sleep N seconds
-> increments shared_counter
-> logs end state
-> returns heap-allocated string (if joinable)

πŸ”₯ Highlights

  • pthread_self() β†’ logs internal thread ID

  • add_log() logs both start and end messages

  • If joinable: malloc() a string and return it to main

  • If detached: return is ignored (no memory leak because it’s never malloced for detached)


🧠 πŸ”„ Main Thread Behavior


πŸ”Ή Phase 1: Launch Threads

args[i].should_detach = (i % 2 == 0);  // Even β†’ detach
 
if (args[i].should_detach)
	pthread_detach(threads[i]);
else
	pthread_join(threads[i], &res);
  • Threads created with shared args[i]

  • Joinable ones will malloc() a return string β†’ main() prints and free()s


πŸ”Ή Phase 2: Join Joinables

if (args[i].should_detach == 0)
{
	pthread_join(...);
	free(res);
}
  • Only join joinables

  • Print return string (e.g. "Thread 3 result")

  • free() the malloc() string safely


πŸ”Ή Phase 3: Final Log Dump

while (i < log_index)
	printf("%s\n", logs[i]);
  • Prints global logs added by worker()

  • Helps debug execution timeline


πŸ”Ή Final Output

printf("Final counter value (racy): %d\n", shared_counter);
  • Shows last value of the shared counter

  • Usually < THREAD_COUNT due to race condition


🧠 Takeaways (FAANG-level Insight)


βœ… What This Teaches:

🧠 ConceptπŸ”Ž Insight
Detach vs JoinDetached threads are β€œfire-and-forget”, unrecoverable
Shared StructsSafe if thread args are not overwritten (e.g., stack array, not heap)
LoggingMutex-wrapped add_log() ensures consistency
Racesshared_counter is buggy by design β€” shows real-world risk
MemoryReturn values from threads must be free()d β€” or they leak
DesignLogs + delays = controlled randomness, great for simulations

πŸ”§ What You Could Improve or Extend

  • Add pthread_mutex_t counter_mutex to make counter race-free βœ…

  • Add pthread_rwlock_t and compare performance πŸ”

  • Log timestamps to see thread overlap in real time ⏱️

  • Use pthread_attr_t to set stack size or detach state explicitly πŸ“


Would you like me to refactor this into:

  • 🧼 [[asymmetric_pthreads/06_mutex_vs_rwlock_under_load]] (with mutex vs rwlock + safe counter)?

  • or do you want to branch into atomic-only variants in [[07_shared_counter_with_mutex]] and [[08_atomic_counter_raceproof]] first?