Concurrency in C Language
Introduction
Concurrency is the ability of a program to execute multiple tasks simultaneously. It is a key concept in modern programming, allowing for efficient utilization of CPU resources. In C, concurrency can be achieved using various techniques such as threads, processes, and asynchronous I/O.
Threads
Threads are the smallest unit of execution within a program. They allow multiple sequences of instructions to be executed concurrently within a single process. In C, threads can be created using the POSIX thread (pthread) library.
Example: Creating and Running a Thread
#include <stdio.h> #include <pthread.h> void* thread_function(void* arg) { printf("Hello from the thread!\n"); return NULL; } int main() { pthread_t thread; pthread_create(&thread, NULL, thread_function, NULL); pthread_join(thread, NULL); printf("Hello from the main thread!\n"); return 0; }
In this example, we create a thread using pthread_create
and wait for it to finish using pthread_join
. The output will be:
Hello from the main thread!
Synchronization
When multiple threads access shared resources, synchronization is necessary to prevent race conditions. Mutexes (mutual exclusions) are used to ensure that only one thread can access a resource at a time.
Example: Using Mutex for Synchronization
#include <stdio.h> #include <pthread.h> pthread_mutex_t lock; void* thread_function(void* arg) { pthread_mutex_lock(&lock); printf("Thread %d: Entering critical section\n", *(int*)arg); printf("Thread %d: Leaving critical section\n", *(int*)arg); pthread_mutex_unlock(&lock); return NULL; } int main() { pthread_t thread1, thread2; int id1 = 1, id2 = 2; pthread_mutex_init(&lock, NULL); pthread_create(&thread1, NULL, thread_function, &id1); pthread_create(&thread2, NULL, thread_function, &id2); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_mutex_destroy(&lock); return 0; }
In this example, we use a mutex to synchronize access to the critical section. The output will ensure that the critical section is accessed by one thread at a time:
Thread 1: Leaving critical section
Thread 2: Entering critical section
Thread 2: Leaving critical section
Deadlock
Deadlock occurs when two or more threads are waiting for each other to release resources, causing them to be stuck indefinitely. Proper design and use of synchronization primitives can help prevent deadlocks.
Example: Potential Deadlock Scenario
#include <stdio.h> #include <pthread.h> pthread_mutex_t lock1, lock2; void* thread_function1(void* arg) { pthread_mutex_lock(&lock1); sleep(1); // Simulate some work pthread_mutex_lock(&lock2); printf("Thread 1: Inside critical section\n"); pthread_mutex_unlock(&lock2); pthread_mutex_unlock(&lock1); return NULL; } void* thread_function2(void* arg) { pthread_mutex_lock(&lock2); sleep(1); // Simulate some work pthread_mutex_lock(&lock1); printf("Thread 2: Inside critical section\n"); pthread_mutex_unlock(&lock1); pthread_mutex_unlock(&lock2); return NULL; } int main() { pthread_t thread1, thread2; pthread_mutex_init(&lock1, NULL); pthread_mutex_init(&lock2, NULL); pthread_create(&thread1, NULL, thread_function1, NULL); pthread_create(&thread2, NULL, thread_function2, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_mutex_destroy(&lock1); pthread_mutex_destroy(&lock2); return 0; }
In this example, the two threads can potentially cause a deadlock if each thread acquires one of the locks and waits for the other lock to be released. To prevent deadlocks, always acquire multiple locks in the same order.
Conclusion
Concurrency is a powerful concept in C programming, allowing multiple tasks to run simultaneously and efficiently. Understanding threads, synchronization, and deadlocks are crucial for writing robust concurrent programs. With proper design and careful use of synchronization primitives, you can harness the full potential of concurrent programming in C.