Multithreading in C

Multithreading in C

Multithreading is a way to achieve parallelism in program execution, allowing multiple threads to run concurrently, improving the performance and responsiveness of applications. In C, the most common library for multithreading is POSIX Threads (often referred to as pthreads).

In this tutorial, we'll cover the basics of multithreading using the pthreads library.

1. Setting up Pthreads:

To use pthreads, you need to include the header:

#include <pthread.h>

And when compiling, you need to link against the pthread library:

gcc program.c -o program -lpthread

2. Creating a Thread:

To create a thread, you use the pthread_create function.

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

3. Basic Example:

Here's a simple example of creating two threads:

#include <stdio.h>
#include <pthread.h>

void *print_message_function(void *ptr) {
    char *message;
    message = (char *) ptr;
    printf("%s \n", message);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    char *message1 = "Thread 1";
    char *message2 = "Thread 2";

    pthread_create(&thread1, NULL, print_message_function, (void *) message1);
    pthread_create(&thread2, NULL, print_message_function, (void *) message2);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

In the above example:

  • Two threads are created, each calling print_message_function.
  • pthread_join is used to make the main thread wait for the created threads to complete.

4. Synchronizing Threads:

Multithreading often requires synchronization mechanisms like mutexes to avoid race conditions. A mutex (short for mutual exclusion) is a synchronization primitive that prevents more than one thread from accessing a resource concurrently.

Declaring a Mutex:

pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;

Using a Mutex:

pthread_mutex_lock(&myMutex);
// Critical section (only one thread can access this at a time)
pthread_mutex_unlock(&myMutex);

5. Thread Termination:

A thread can be terminated using pthread_exit:

pthread_exit(void *retval);

This function terminates the calling thread and returns a value via retval.

6. Other Concepts:

  • Thread Attributes: You can set various attributes for your threads, such as detach state, stack size, etc., using thread attributes.
  • Thread-specific Data: Sometimes you need thread-local storage, i.e., data specific to each thread.
  • Condition Variables: These are used for signaling between threads. If a thread wants to wait for a particular condition to be true, it can wait on a condition variable.

7. Considerations:

  • Deadlocks: If two or more threads are waiting for each other to release resources, they can enter a state where they're stuck. This is called a deadlock. Always ensure you acquire and release locks in a consistent order.
  • Race Conditions: Occur when the behavior of a program depends on the relative timing of events, such as the order in which threads are scheduled.

8. Conclusion:

Multithreading allows for concurrent execution, making applications more efficient, especially on multi-core processors. However, with this power comes complexity. Proper synchronization, understanding of shared resources, and careful design are essential to avoid common pitfalls like race conditions and deadlocks. Always consider whether the benefits of multithreading outweigh the added complexity in your specific application.


More Tags

react-16 ohhttpstubs counter urlencode export-to-csv xssf database-schema angular-http-interceptors samesite custom-post-type

More Programming Guides

Other Guides

More Programming Examples