Multi-threading in C/C++

Section 9: Multi-threading in C/C++

Lesson 1: Multithreading Concepts

1.1 Introduction to Multithreading

Multithreading is a programming concept where multiple threads within a process execute independently, sharing the same resources. Threads provide concurrent execution, enhancing program performance and responsiveness.


1.2 Advantages of Multithreading


Lesson 2: Basics of Multithreading in C/C++

2.1 Creating Threads

Multithreading in C/C++ involves creating and managing threads using library functions. In C, the pthread library is commonly used.

Example (Creating Threads in C):

#include <stdio.h>

#include <pthread.h>


// Function executed by the thread

void* threadFunction(void* arg) {

    printf("Thread is running!\n");

    return NULL;

}


int main() {

    // Thread identifier

    pthread_t threadId;


    // Create a thread

    int result = pthread_create(&threadId, NULL, threadFunction, NULL);

    if (result == 0) {

        printf("Thread created successfully!\n");


        // Wait for the thread to finish

        pthread_join(threadId, NULL);

        printf("Thread finished!\n");

    } else {

        fprintf(stderr, "Failed to create thread!\n");

    }


    return 0;

}


2.2 Thread Synchronization

Synchronization mechanisms prevent data races and ensure orderly execution of threads. Mutexes and condition variables are commonly used for synchronization.

Example (Mutex for Synchronization in C): 

#include <stdio.h>

#include <pthread.h>


// Shared resource

int sharedData = 0;


// Mutex for synchronization

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


// Function executed by the thread

void* threadFunction(void* arg) {

    for (int i = 0; i < 5; ++i) {

        // Acquire the mutex

        pthread_mutex_lock(&mutex);


        // Modify the shared resource

        ++sharedData;

        printf("Thread: %d\n", sharedData);


        // Release the mutex

        pthread_mutex_unlock(&mutex);

    }

    return NULL;

}


int main() {

    pthread_t threadId;


    // Create a thread

    int result = pthread_create(&threadId, NULL, threadFunction, NULL);

    if (result == 0) {

        // Wait for the thread to finish

        pthread_join(threadId, NULL);

    } else {

        fprintf(stderr, "Failed to create thread!\n");

    }


    return 0;

}


Lesson 3: Synchronization Mechanisms

3.1 Mutexes

Mutexes (Mutual Exclusion) are used to protect shared resources from simultaneous access by multiple threads. They ensure that only one thread can access the critical section at a time.

Example (Mutex Usage in C++):

#include <iostream>

#include <thread>

#include <mutex>


// Shared resource

int sharedData = 0;


// Mutex for synchronization

std::mutex myMutex;


// Function executed by the thread

void threadFunction() {

    for (int i = 0; i < 5; ++i) {

        // Lock the mutex

        std::lock_guard<std::mutex> lock(myMutex);


        // Modify the shared resource

        ++sharedData;

        std::cout << "Thread: " << sharedData << std::endl;

    }

}


int main() {

    std::thread myThread(threadFunction);


    // Wait for the thread to finish

    myThread.join();


    return 0;

}


3.2 Condition Variables

Condition variables are used to synchronize the execution of threads based on certain conditions. They are often used with mutexes to achieve controlled access to shared resources.

Example (Condition Variable in C++): 

#include <iostream>

#include <thread>

#include <mutex>

#include <condition_variable>


// Shared resource

int sharedData = 0;


// Mutex for synchronization

std::mutex myMutex;


// Condition variable

std::condition_variable myCondition;


// Flag indicating whether the condition is met

bool conditionMet = false;


// Function executed by the thread

void threadFunction() {

    for (int i = 0; i < 5; ++i) {

        // Lock the mutex

        std::unique_lock<std::mutex> lock(myMutex);


        // Wait until the condition is met

        myCondition.wait(lock, [] { return conditionMet; });


        // Modify the shared resource

        ++sharedData;

        std::cout << "Thread: " << sharedData << std::endl;


        // Reset the condition

        conditionMet = false;

        lock.unlock();

        myCondition.notify_one();

    }

}


int main() {

    std::thread myThread(threadFunction);


    // Notify the thread that the condition is met

    {

        std::lock_guard<std::mutex> lock(myMutex);

        conditionMet = true;

    }

    myCondition.notify_one();


    // Wait for the thread to finish

    myThread.join();


    return 0;

}

Understanding multithreading concepts and using synchronization mechanisms like mutexes and condition variables is crucial for developing concurrent and efficient C and C++ programs. Practice creating threads, managing shared resources, and implementing synchronization to build robust multithreaded applications.