0% found this document useful (0 votes)
6 views9 pages

Concurrent Systems and Multithreading

The document provides an overview of concurrent systems and multithreading, explaining key concepts such as concurrency, multithreading, and the differences between pthread and std::thread. It details the basic elements of a multithreaded C++ program, including thread creation, synchronization, and the thread lifecycle. Additionally, it addresses race conditions and their resolution using mutexes to ensure safe access to shared resources.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views9 pages

Concurrent Systems and Multithreading

The document provides an overview of concurrent systems and multithreading, explaining key concepts such as concurrency, multithreading, and the differences between pthread and std::thread. It details the basic elements of a multithreaded C++ program, including thread creation, synchronization, and the thread lifecycle. Additionally, it addresses race conditions and their resolution using mutexes to ensure safe access to shared resources.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

Concurrent Systems and Multithreading

Introduction to Concurrent Systems & Multithreading :

 Concurrent system: A system where multiple tasks appear to run at the same time (can be
truly parallel or interleaved on a single CPU).
 Multithreading: A way to achieve concurrency by running multiple threads (lightweight units
of a process) simultaneously.

Example:

 Imagine a video player: one thread handles video, one handles audio, and another listens for
keyboard input.

Concurrency (the concept):

Concurrency is the ability of a system to handle multiple tasks at once (or appear to).

It’s about designing software that can:

 Deal with many things happening at once,

 Switch between tasks smoothly,

 Improve responsiveness and efficiency.

Example: A single-core CPU running multiple threads using context switching.

(Single-Core CPU + Multiple Threads = Concurrency via Context Switching)


A single-core CPU can run multiple threads by rapidly switching between them.
This is called Concurrency.

(Multi-Core CPU + Multiple Threads = True Parallelism)


When you have a multi-core CPU, each core can run a different thread at the same time.
That means No switching needed.

Concurrent Systems (the system built with that concept):

A Concurrent System is a system designed using concurrency.

It could be:

 A multithreaded program,

 An operating system handling many users or apps at once,

 A server handling multiple client requests.


Concurrent Systems and Multithreading
Basic Elements of a Multithreaded C++ Program / (The main
parts or building blocks of Multithreading)

Here are the main parts you'll work with:

1. Threads :
Small independent units of execution inside a program.
🧵 In C++, threads are created using the std::thread class (from the <thread> header).
Eg :
std::thread t1(task1);

2. Functions to Execute :
Each thread needs a function or callable to run.
Eg.
void task1() {
std::cout << "Running task 1\n";
}
3. Thread Creation :
Launch the thread by passing the function to std::thread.
Eg. std::thread t1(task1); // t1 runs task1

4. Synchronization :
Managing shared resources to prevent conflicts between threads.
🛑 For this, we use things like:
 std::mutex (mutual exclusion)
 std::lock_guard (auto-lock)
 std::unique_lock
Eg.
std::mutex m;
void task() {
std::lock_guard<std::mutex> lock(m);
// Safe access here
}

5. Joining Threads :
Wait for threads to finish before the program ends.
Eg.
t1.join(); // Main thread waits for t1

6. Detaching Threads (Optional) :


Let a thread run independently (like in background).
Concurrent Systems and Multithreading
Eg.
t1.detach();
Element Purpose
std::thread Creates and manages a thread
Function/Callable The task to run
join() Waits for the thread to finish
detach() Lets thread run in background
mutex Prevents data conflicts
lock_guard Automatically locks/unlocks a mutex

Multi-Thread sample Program:


#include <iostream>
#include <thread>

void task1() {
std::cout << "Task 1 running\n";
}

void task2() {
std::cout << "Task 2 running\n";
}

int main() {
std::thread t1(task1); // runs concurrently
std::thread t2(task2); // runs concurrently

t1.join();
t2.join();
}

Possible Output:

Task 1 running
Task 2 running

OR

Task 2 running
Task 1 running

OR (Rare, if threads interleave at consol level)


Concurrent Systems and Multithreading
Task 2 runTask 1 running
OR
Task 1 runTask 2 running

Introduction pthread.h and thread :

1. pthread.h (POSIX Threads) Portable Operating System Interface (uniX):


What is it?

 pthread stands for POSIX Threads (Portable Operating System Interface (uniX)).
 It is a C-style thread library used in UNIX/Linux systems.
 It is lower-level and gives you manual control over threads.

2. std::thread (C++11 Standard Threads)


What is it?

 std::thread is the modern C++ way to create and manage threads.


 Introduced in C++11.
 Easier to use and more type-safe than pthread.

Header file: #include <thread>

Sample code:
#include <iostream>
#include <thread>
using namespace std;

void task() {
cout << "Thread running using std::thread\n";
}

int main() {
thread t1(task); // Start thread
t1.join(); // Wait for it to finish
return 0;
}

Difference Between pthread and std::thread

Feature pthread std::thread


Language C-style (used in C/C++) C++11 and above
Easier to use ❌ (more complex) ✅ (more user-friendly)
Portability Mostly POSIX (Linux) Cross-platform (Linux/Windows)
Concurrent Systems and Multithreading
Type Safety ❌ ✅
Integration with C++ ❌ Less ✅ Great (supports lambdas, classes)

In C++ you can pass a class (or more precisely, a callable object) to a thread
instead of a function.

What is operator()?

The operator() in a class makes an object behave like a function.


Such objects are called functors or function objects.

Sample code:

#include <iostream>
#include <thread>
using namespace std;

// Define a class with operator() (Functor)


class Task {
public:
void operator()() {
cout << "Thread running using class (functor)\n";
}
};

int main() {
Task taskObj;
thread t1(taskObj); // Pass class object to thread
t1.join();
return 0;
}

Output:
Thread running using class (functor)

Thread Lifecycle in C++


1. New (Created)

 Description: A thread object is created, but the thread itself hasn't started running yet.
 Syntax:

std::thread t(myFunction); // 't' is created, but not yet running.


Concurrent Systems and Multithreading
2. Runnable (Ready to Run)

 Description: After a thread is created, it becomes runnable. This means the thread is ready and
waiting for the operating system to assign it CPU time to actually run the function.
 Syntax:

std::thread t(myFunction); // thread is now ready and waiting to run.

3. Running

 Description: The thread starts running the function you assigned to it. This happens when the
thread gets CPU time.
 Syntax (in the function you want the thread to run):

void myFunction() {
std::cout << "Thread is running!" << std::endl;
}

4. Waiting / Blocked (Optional)

 Description: Sometimes a thread might wait or be blocked (e.g., waiting for data, waiting to
acquire a lock, etc.). This can happen if you use sleep, or if you are synchronizing threads using a
mutex.
 Syntax (blocking with sleep/mutex):
1. std::this_thread::sleep_for(std::chrono::seconds(2)); // simulates waiting/blocking
2. std::mutex mtx; // Mutex for synchronization
void threadFunction(int id) {
std::cout << "Thread " << id << ": Trying to lock the mutex...\n";

mtx.lock(); // Thread tries to lock the mutex, blocking if it's already locked by another
thread
std::cout << "Thread " << id << ": Got the lock!\n";

// Simulate some work (this is the critical section)


std::this_thread::sleep_for(std::chrono::seconds(2));

std::cout << "Thread " << id << ": Finished work, unlocking the mutex.\n";
mtx.unlock(); // Unlock the mutex so others can acquire it
}

5. Terminated (Finished)

 Description: Once the thread finishes its work, it is terminated. The thread has completed its
execution and can be joined with the main thread.
 Syntax:

t.join(); // Waits for the thread to finish


Concurrent Systems and Multithreading

Understanding Shared Memory Model and its


Challenges during race condition

What is Race Condition : A race condition occurs when two or more threads try to access and modify
shared data at the same time in an unpredictable way. Because of this, the final outcome of the
program may be different each time it runs, depending on the order in which the threads run.

In simpler terms:

When threads "race" to access shared data, and the result depends on who gets there first. 🏁

🧠 Key Concept:

 Multiple threads are competing (racing) to change shared data.


 Without proper synchronization, the result can be unpredictable and cause errors.

Sample code :

#include <iostream>
#include <thread>
using namespace std;

int counter = 0; // Shared variable

// Function to increment the counter


void increment() {
for (int i = 0; i < 100000; i++) {
counter++; // Increment the shared counter
}
}

int main() {
thread t1(increment); // Thread 1
thread t2(increment); // Thread 2

t1.join(); // Wait for t1 to finish


t2.join(); // Wait for t2 to finish

cout << "Final counter value: " << counter << endl;
return 0;
}
Concurrent Systems and Multithreading
Output :
May / May not be 200000

🔴 Race Condition Here:

 Both t1 and t2 are incrementing the same counter variable.


 The threads may access counter at the same time, causing incorrect updates to the variable.
 Counter may not increment correctly because the threads "race" to read and write the value.

🧠 Why does this happen?

 Each thread reads the value of counter, increments it, and writes it back. If two threads do this
at the same time, they may overwrite each other’s changes, leading to errors.

🚀 Example of a Wrong Output:

 Since the threads are racing, the final value of counter may not be 200000 (which it should
be, because each thread increments it by 100,000).
 It could be much smaller due to lost updates!

How to Fix a Race Condition?

Sample code :

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

int counter = 0; // Shared variable


mutex m; // Mutex to lock critical section

// Function to increment the counter


void increment() {
for (int i = 0; i < 100000; i++) {
m.lock(); // Lock before modifying shared data
counter++; // Increment the shared counter
m.unlock(); // Unlock after modification
}
}

int main() {
Concurrent Systems and Multithreading
thread t1(increment); // Thread 1
thread t2(increment); // Thread 2

t1.join(); // Wait for t1 to finish


t2.join(); // Wait for t2 to finish

cout << "Final counter value: " << counter << endl;
return 0;
}

Output :
200000

✅ Mutex:

 Using mutex ensures that only one thread can access the shared counter at a time.
 This prevents race conditions and gives you the correct result!

You might also like