week_9
week_9
Lock(Mutex) Lock(Mutex)
Definition: Usage:
Mutexes are typically used in critical sections of code, where shared
A lock, usually called a mutex, is a fundamental resources are accessed or modified.
primitive for synchronization that permits mutual Before entering a critical section, a thread locks the mutex, ensuring
exclusive access to the resource.
exclusion. After completing its work in the critical section, the thread unlocks the
A mutex (short for mutual exclusion) is a mutex, allowing other threads to access the resource.
synchronization mechanism used to control access to Operations:
Locking: A thread locks a mutex before entering a critical section using
shared resources in a multithreaded environment. operations like pthread_mutex_lock() in POSIX threads or std::mutex::lock()
in C++.
While other threads wait for the lock to be released, it
If the mutex is already locked by another thread, the calling
ensures that only one thread can ever acquire the lock. thread blocks until the mutex becomes available.
It allows only one thread at a time to access a shared Unlocking: After completing its work in the critical section, the thread
unlocks the mutex using operations like pthread_mutex_unlock() in POSIX
resource, ensuring that concurrent access by multiple threads or std::mutex::unlock() in C++.
threads doesn't lead to data corruption or inconsistency. This allows other threads waiting on the mutex to acquire it and
enter the critical section.
Lock(Mutex) Lock(Mutex)
you could categorize threads broadly into two types: POSIX
threads and Windows threads. The underlying logic and concepts of
POSIX Threads (pthreads): threading are the same regardless of the
POSIX threads are standardized threads based on the POSIX
standard. threading model or API used.
POSIX stands for "Portable Operating System Interface".
It's a family of standards that define the interface between an However, the names of the methods,
operating system and application software.
POSIX-compliant operating systems adhere to these standards,
functions, and synchronization primitives
ensuring compatibility across different systems. differ between POSIX threads and Windows
They are commonly used in Unix and Unix-like operating systems threads.
such as Linux, macOS, and various flavors of Unix.
Functions and synchronization primitives are provided by the Here's a comparison:
pthreads API, such as pthread_create(), mutexes, condition
variables, etc.
Lock(Mutex) Lock(Mutex)
Creating Threads: Mutexes:
POSIX Threads: POSIX Threads:
pthread_create(pthread_t *thread, const pthread_mutex_t mutex =
pthread_attr_t *attr, void PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
*(*start_routine)(void *), void *arg); pthread_mutex_unlock(&mutex);
Windows Threads: Windows Threads:
CreateThread(LPSECURITY_ATTRIBUTES CRITICAL_SECTION cs;
lpThreadAttributes, SIZE_T dwStackSize, InitializeCriticalSection(&cs);
LPTHREAD_START_ EnterCriticalSection(&cs);
LeaveCriticalSection(&cs);
Lock(Mutex) Lock(Mutex)
Deadlock Deadlock
If we have two threads: thread_function1 and
thread_function2. And we have two mutexes.
Each thread locks one mutex and then attempts to lock
the other mutex.
If both threads lock one mutex and then attempt to lock
the other mutex, they may end up waiting indefinitely for
each other to release the mutex they need, resulting in a
deadlock.
To prevent deadlocks, it's crucial to acquire mutexes in a
consistent order across all threads. In the example
above, if both threads always locked mutex1 before
mutex2 or vice versa, a deadlock would be avoided.
Deadlock Semaphore
A semaphore is a synchronization object that
maintains a count.
It allows multiple threads to enter a critical
section up to a specified limit.
If the limit is reached, subsequent threads
will be blocked until a thread releases the
semaphore.
Semaphore Semaphore
Consider a scenario where we have a We initialize a semaphore connection_sem with an
shared resource (e.g., a database initial value of MAX_CONNECTIONS, which
connection, a file, etc.), and we want to limit represents the maximum number of connections
allowed simultaneously.
the number of threads that can access this
resource simultaneously.
We'll use a semaphore to achieve this.
Semaphore Semaphore
Each thread, before accessing the shared resource After the thread finishes using the resource, it calls
(here, simply printing a message), must call sem_post(&connection_sem) to increment the
sem_wait(&connection_sem) to decrement the semaphore, indicating that it's done with the
semaphore. If the semaphore's value is greater resource.
than zero, the thread continues; otherwise, it
blocks until a connection is available.