Multithreading Interview: Interview Questions on Thread Synchronization and Communication in C

Multithreading Interview: Interview Questions on Thread Synchronization and Communication in C

In multithreaded programming, thread synchronization and communication are very important topics. These concepts not only help programmers avoid data conflicts but also ensure effective collaboration between multiple threads. This article will explain these fundamental concepts in detail and demonstrate their implementation in C language through example code.

1. Understanding Multithreading

Multithreading refers to the concurrent execution of multiple execution paths (or “threads”) within the same process. Multithreading can enhance the performance of applications, but it also brings many challenges, such as resource sharing and data consistency issues.

2. Linear Problems and Solutions

2.1 Data Race

A data race occurs when multiple threads concurrently access the same variable, and at least one of them is performing a write operation, which can lead to unpredictable results.

Example Code: Data Race

Below is a simple example of a data race:

#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 10
int counter = 0; // Global counter
void* increment(void* arg) {
    for (int i = 0; i < 10000; i++) {
        counter++; // Data race point
    }
    return NULL;
}
int main() {
    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&threads[i], NULL, increment, NULL);
    }
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    printf("Final counter: %d\n", counter); // Output is unpredictable
    return 0;
}

Explanation: In the above code, we create 10 threads, each of which increments the <span>counter</span> 10,000 times. Since no synchronization mechanism is used, modifications to <span>counter</span> will lead to a data race, and the final printed result is also unpredictable.

2.2 Using Mutex to Solve Data Race

To avoid the above issues, a mutex can be used to protect shared resources, ensuring that only one thread can access the resource at a time.

Example Code: Using Mutex to Protect Shared Resource

#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 10
int counter = 0;
pthread_mutex_t lock;
void* increment(void* arg) {
    for (int i = 0; i < 10000; i++) {
        pthread_mutex_lock(&lock); // Lock
        counter++;
        pthread_mutex_unlock(&lock); // Unlock
    }
    return NULL;
}
int main() {
    pthread_t threads[NUM_THREADS];
    // Initialize mutex
    pthread_mutex_init(&lock, NULL);
    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_create(&threads[i], NULL, increment, NULL);
    }
    for (int j = 0; j < NUM_THREADS; j++) {
        pthread_join(threads[j], NULL);
    }
    printf("Final counter: %d\n", counter); // Output is predictable
    pthread_mutex_destroy(&lock);
    return 0;
}

In this code, we use a mutex to protect the <span>counter</span> variable. Each thread locks the mutex before modifying the counter and unlocks it afterward, ensuring that only one thread can modify the counter at a time, thus preventing data races.

Leave a Comment