Threads

std::thread is the standard C++11 way to spawn a new OS-level thread. Each std::thread object represents a single, joinable thread of execution. Under the hood, on Linux/Android, it wraps pthread_create() and uses native threads

Creating a simple thread

#include <iostream>
#include <thread>

void say_hello() {
    std::cout << "Hello from thread!\n";
}

int main() {
    std::thread t(say_hello); // Spawn new thread
    t.join(); // Wait for thread to finish
    std::cout << "Back in main()\n";
    return 0;
}

Important points to note

.join() -> Waits for the thread to complete (like pthread_join)
.detach() -> Lets thread run independently (becomes un-joinable)
RAII danger -> If std::thread is not joined or detached before destruction → crash

Thread as a class Member

Creating a local variable looks easy, but how to init a thread if thread is member of a class, you need to mention exact scoped function and this pointer while creating the thread, ie.
worker_thread = std::thread(&Worker::run, this);

#include <iostream>
#include <thread>
#include <atomic>

class Worker {
public:
    Worker() : running(false) {}

    void start() {
        running = true;
        worker_thread = std::thread(&Worker::run, this);
    }

    void stop() {
        running = false;
        if (worker_thread.joinable()) {
            worker_thread.join();
        }
    }

    ~Worker() {
        stop();
    }

private:
    void run() {
        while (running) {
            std::cout << "Running in worker thread\n";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

    std::atomic<bool> running;
    std::thread worker_thread;
};

Setting thread’s name

pthread_setname_np(pthread_self(), name); // Max 15 chars , This API can be used to set thread name.

Setting Thread priority

In Scheduling article, we talked about different schedulings like RT, then different priorities. For that we can use pthread_setschedparam to evelvate the priority. RT priorities need CAP_SYS_NICE permission, you can define it in a rc file in Android.

void elevate_priority(int prio = 80) {
    sched_param sch_params;
    sch_params.sched_priority = prio;

    if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch_params) != 0) {
        perror("Failed to set thread priority");
    } else {
        std::cout << "Priority set to " << prio << "\n";
    }
}

Critical Section and data race

When multiple threads try to access same global variable, it can cause data race, we can use mutex to prevent it.

A std::mutex ensures that only one thread at a time can enter a critical section — any other thread trying to acquire the lock will block until it’s released. It maps directly to a binary semaphore or lock in OS kernels

Try running below code , from multiple threads, you may get a incorrect ans.

int counter = 0;

void unsafe_increment() {
    for (int i = 0; i < 10000; ++i) {
        ++counter;
    }
}
// by the end should be 10000 + 10000, if 2 threads are calling this function, but it may not be the ans, because of data race.

We can simply use a mutex to prevent data racing.

std::mutex counter_mutex;

void safe_increment() {
    for (int i = 0; i < 10000; ++i) {
        std::lock_guard<std::mutex> lock(counter_mutex);
        ++counter;
    }
}

There are multiple lock_guard, this table represents their uses, as per task these can be used.

GoalUse ThisWhy
Just protect critical sectionstd::lock_guardSmall scope, RAII, low overhead
Use with condition_variablestd::unique_lockRequired for .wait(lock)
Need to unlock earlystd::unique_lockAllows lock.unlock() mid-scope
Lock multiple mutexes safelystd::scoped_lock(m1, m2)Avoids deadlocks via atomic lock ordering
Allow multiple readersstd::shared_mutexOne writer or many readers at once
Want full manual controlstd::mutexMore error-prone, but flexible

std::mutex m;
m.lock();
// critical section
m.unlock();
std::lock_guard<std::mutex> lock(m);
// auto-unlocked when lock goes out of scope

std::unique_lock<std::mutex> lock(m);
cond_var.wait(lock);  // required with cond vars
lock.unlock();        // manually unlock if needed
std::mutex a, b;
std::scoped_lock lock(a, b); // Avoid deadlock when locking multiple mutexes

std::shared_mutex sm;
void reader() {
    std::shared_lock lock(sm);  // Many readers can hold this
}
void writer() {
    std::unique_lock lock(sm);  // Only one writer allowed
}

Communication b/w threads

A condition_variable allows one thread to wait until it’s told by another thread that a condition has changed. It’s the thread-safe alternative to:
polling loops (CPU waste),
busy-waiting (while(!ready) {}),

Interesting thing note here is the wait condition
cv.wait(lock, [] { return ready; }); it is called the predicate, it is read as wait until predicate is true, ie if the predicate is false then thread will wait other it won’t wait.

#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; });  // Wait until `ready == true`
    std::cout << "Worker thread proceeding...\n";
}

void signaler() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();  // Wake one thread
}

int main() {
    std::thread t1(worker);
    std::thread t2(signaler);
    t1.join();
    t2.join();
}

cv.wait(lock):

  • Unlocks the mutex.
  • Blocks the thread on a kernel futex wait.
  • Re-locks the mutex after being signaled.

cv.notify_one() or notify_all():

  • Signals a waiting thread to re-acquire the mutex and proceed.
FunctionPurpose
cv.wait(lock, predicate)Wait until signaled and predicate is true
cv.notify_one()Wake one waiting thread
cv.notify_all()Wake all waiting threads
wait_for()Timed wait
wait_until()Deadline-based wait

Leave a comment

It’s Jdecoder

I am trying to decode the concepts into simple words and documenting items i know or currently learning.

Let’s connect

Design a site like this with WordPress.com
Get started