Concurrency and Multithreading Questions
Principles and practical techniques for concurrent execution and safe access to shared state across threads or execution contexts. Covers synchronization primitives (locks, mutexes, semaphores, condition variables), atomic operations and memory ordering, avoiding deadlocks, race conditions, and livelocks, designing thread safe data structures, thread pools and work scheduling, and asynchronous or event driven execution models such as coroutines, futures and promises, and reactive streams. Also covers platform and language specific concurrency tools, for example java.util.concurrent and POSIX threads on backend systems, Grand Central Dispatch and OperationQueue on iOS, coroutines and structured concurrency on Android/Kotlin, and async/await models in other languages. Evaluations focus on reasoning about correctness under concurrent access, performance trade offs (throughput, latency, contention), and preventing blocking of latency sensitive execution paths (server request handlers, UI threads, game loops) to maintain responsiveness.
Sample Answer
// C++ (POSIX-ish) illustrative sketch
#include <pthread.h>
#include <sys/types.h>
#include <map>
#include <set>
#include <mutex>
#include <thread>
class PI_Mutex {
pthread_mutex_t mtx;
std::mutex meta; // protect metadata
pthread_t owner = 0;
int owner_orig_prio = 0;
std::multiset<int> waiters; // store waiting priorities (higher number = higher priority)
int get_thread_priority(pthread_t t) {
sched_param sp; int policy;
pthread_getschedparam(t, &policy, &sp);
return sp.sched_priority;
}
void set_thread_priority(pthread_t t, int prio) {
sched_param sp{prio};
pthread_setschedparam(t, SCHED_FIFO, &sp); // error checks omitted
}
public:
PI_Mutex() { pthread_mutex_init(&mtx,nullptr); }
~PI_Mutex(){ pthread_mutex_destroy(&mtx); }
void lock() {
pthread_t self = pthread_self();
int self_prio = get_thread_priority(self);
{
std::unique_lock<std::mutex> lk(meta);
// if someone owns it, record our priority and boost owner
if (owner != 0) {
waiters.insert(self_prio);
int max_wait = *waiters.rbegin();
int owner_cur = get_thread_priority(owner);
if (max_wait > owner_cur) {
// boost owner
set_thread_priority(owner, max_wait);
}
}
}
pthread_mutex_lock(&mtx);
// we've acquired the mutex: become owner
std::unique_lock<std::mutex> lk(meta);
owner = self;
owner_orig_prio = self_prio; // store original (simplified)
// remove self from waiters if it was present
auto it = waiters.find(self_prio);
if (it != waiters.end()) waiters.erase(it);
}
void unlock() {
std::unique_lock<std::mutex> lk(meta);
if (owner != pthread_self()) {
// error: unlocking by non-owner (omitted)
}
// compute highest waiting priority (if any)
int new_prio = owner_orig_prio;
if (!waiters.empty()) new_prio = std::max(new_prio, *waiters.rbegin());
// restore owner (or set to next needed) before releasing
set_thread_priority(owner, owner_orig_prio);
owner = 0;
owner_orig_prio = 0;
lk.unlock();
pthread_mutex_unlock(&mtx);
}
};Sample Answer
#include <atomic>
#include <thread>
#include <cassert>
std::atomic<int> data{0};
std::atomic<bool> ready{false};
void producer_relaxed() {
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_relaxed); // may be visible before data
}
void consumer_relaxed() {
while (!ready.load(std::memory_order_relaxed)) {}
// Could see ready==true but still read data==0 due to reordering
int v = data.load(std::memory_order_relaxed);
// v might be 0 here with relaxed semantics
}
void producer_release() {
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_release); // publishes prior stores
}
void consumer_acquire() {
while (!ready.load(std::memory_order_acquire)) {}
int v = data.load(std::memory_order_relaxed);
// v must be 42: acquire pairs with release to synchronize
}Sample Answer
Sample Answer
Sample Answer
Unlock Full Question Bank
Get access to hundreds of Concurrency and Multithreading interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.