Semaphore in C++
A semaphore is a synchronization primitive used to manipulate get entry to shared assets in a concurrent or multi-threaded context. It allows several threads to accomplish that at the same time as limiting the quantity of threads. Semaphores are a beneficial tool for preventing racial tensions and useful resource conflicts.
The idea of semaphores turned into evolved via Edsger W. Dijkstra in 1960s, and there are two kinds: counting semaphores and binary semaphores (which receive any non-zero integer as a shipping).
![Semaphore in C++](https://static.tutorialandexample.com/cpp/semaphore-in-cpp1.png)
Types of semaphores
The primary types of semaphores are as follows:
1) Binary Semaphore
Only the numbers zero and 1 can be used to discover a binary semaphore, that is a completely distinct sort of semaphore. It features further to a mutex or lock, with a price of one representing a usable aid this is now available (unlocked) and a price of zero indicating that the useful resource is locked (presently in use).
2) Counting Semaphore
A counting semaphore can be created using any non-negative integer fee. It permits many threads to get entry to the shared aid as much as a set maximum constraint. Once a semaphore has reached its most ability, all extra threads attempting to use it is going to be blocked till some other threads relinquish it and decrease the semaphore be counted.
Example:
#include <iostream>
#include <thread>
// Shared resource
int sharedResource = 0;
// Define a counting semaphore with an initial count of 1
//std::counting_semaphore<1> semaphore;
// Function executed by each thread
void accessSharedResource(int threadId) {
//semaphore.acquire(); // Wait until the semaphore count is greater than zero, then decrement it
// Critical section (access shared resource)
sharedResource++;
std::cout << "Thread " << threadId << " accessed the shared resource. Current value: " << sharedResource << std::endl;
//semaphore.release(); // Increment the semaphore count
}
int main() {
// Create multiple threads that access the shared resource
std::thread t1(accessSharedResource, 1);
std::thread t2(accessSharedResource, 2);
std::thread t3(accessSharedResource, 3);
// Join the threads with the main thread
t1.join();
t2.join();
t3.join();
return 0;
}
Output:
![Semaphore in C++](https://static.tutorialandexample.com/cpp/semaphore-in-cpp2.png)
The semaphore on this output limits the variety of concurrent accesses to the shared useful resource, causing every of the 3 threads (1, 2, and three) to enter the important vicinity sequentially. The sharedResource variable, that's up to date and displayed inside the output, receives one addition from each thread.
Operations performed in Semaphores
1) wait() or acquire(): The acquire() motion may be utilized by a thread or system to request access to a shared useful resource this is semaphore-protected. If the semaphore remember is more than zero, the thread is furnished access and the semaphore depend is reduced. If the be counted price is zero, which indicates that a couple of threads are guarding the semaphore until it becomes available (a few other thread uses release()), the querying thread can be blocked (placed to sleep).
2) release() or sign(): When a thread or technique makes use of the release() technique to suggest that it has completed inquiring for access to a shared aid, the semaphore is released. As the semaphore expands, this motion allows for the holding of additional waiting threads.
Semaphore vs Mutex
Semaphore | Mutex | |
Functionality | A semaphore, a regularly occurring synchronization primitive, can start with a count better than 1. It allows a predetermined range of threads to apply the shared resource without delay, as shown via the semaphore's depend. Semaphores can be utilized in greater complicated situations, together with dealing with constrained assets or making sure that a certain sort of thread can use a resource right away. | A mutex is a primitive for binary synchronization with a depends of 1. Mutual exclusion is called a mutex. Since it most effective lets in one thread to get admission to the shared aid at a time, it effectively offers extraordinary access to it. Mutexes are often used to shield touchy areas with most effective one thread. |
Operations | Semaphores use the (acquire() or wait() or P()) and (release() or sign() or V()) features to request and release get admission to the shared resource. | Mutexes use the lock() and unlock() strategies to restriction character get entry to the shared useful resource and launch it. |
Counting | Using counting semaphores with counts more than zero, several threads can also get entry to the shared aid concurrently up to the predetermined restriction. | Due to its binary nature and dependence on 1, one thread can handiest ever harvest a mutex at a time. |
Uses of Semaphore
- Binary semaphore of mutual exclusion: A binary semaphore of mutual exclusion ensures that simplest one thread at a time can get entry to a vital section of code or a shared aid. Utilizing binary semaphores which additionally function as locks or mutexes—mutual exclusion is used.
- Management of the Resource Pool: Managing a restricted number of sources (composed of threads, network connections, or database connections) is called resource pool control (counting semaphore). By keeping tune of semaphores, it's miles viable to limit the number of assets that can be used simultaneously.
- Consumer-Producer Issue: Coordinating the spoken change of statistics throughout threads that may constitute clients and manufacturers. Semaphores can be used to manipulate buffer area and make certain that the manufacturer does not overwrite statistics before the purchaser has processed it.
- Readers-Writers Problem: The readers-writers hassle is while more than one reader or an unmarried creator are given get admission to shared facts. Semaphores can be applied to provide readers and writers priority get right of entry to at the same time as preventing writers from going hungry.
- Barrier synchronization: When a group of threads is coordinated, they every wait until the opposite threads attain a particular point before shifting on. Semaphores may be used for barrier synchronization, which coordinates the execution of parallel tasks.
- Thread Pool Management: Managing a hard and fast-length thread pool so that a exact variety of threads can execute sports concurrently is known as thread pool control. Semaphores can be used to govern the variety of available pooled threads.
- Concurrency Control in Dining Philosophers Problem: A solution to the trouble that stops starvation while using chopsticks. Chopsticks may be notion of as semaphores, which may be used to govern get entry to them and prevent stalemates.
- Task Scheduling and Synchronization: Scheduling and synchronization of obligations in structures that use parallel techniques or parallel processing.
- Producer-Consumer with Multiple Buffers: The manufacturer-purchaser conundrum is expanded using more than one buffers and the use of semaphores to control get right of entry to.
Advantages of Semaphore
Synchronization and Coordination:
Semaphores provide a mechanism to synchronize and coordinate the way that numerous threads have get admission to shared resources. By preventing race circumstances and ensuring that crucial code additives are completed by way of simply one thread at a time, they aid in retaining the consistency of the statistics.
Mutual Exclusion:
Binary semaphores feature as actual locks or mutexes to stop numerous threads from gaining the semaphore right away. This is referred to as mutual exclusion. The term for this is mutual exclusion. This guarantees mutual exclusion and stops simultaneous get right of entry to shared assets, safeguarding them in opposition to concurrent alternate.
Resource Management:
Counting semaphores makes it less complicated to control constrained assets, along with database connections, community connections, or threads. By setting a most restrict on the semaphore remember, you could manage the range of resources that may be used simultaneously and prevent aid opposition.
Deadlock Avoidance:
Avoiding deadlocks is viable with carefully concept-out semaphore utilization, which prevents threads from turning into stalled at the same time as they anticipate each other to launch assets. By controlling the order in which threads acquire semaphores and making sure they launch them inside the proper area, deadlocks may be averted.
Thread Synchronization:
Semaphores provide a way to synchronize threads through letting them watch for particular activities earlier than persevering with. This is quite beneficial while threads need to coordinate their execution or assume the occurrence of a shared event.
Disadvantages of Semaphore:
Complexity and Potential for Bugs:
Semaphores have the ability to increase the complexity of the code and the threat of problems. If semaphores are utilized or handled incorrectly, they may motive deadlocks, race situations, or even crashes. Debugging and fixing such problems is simply difficult.
Thread Management Overhead:
Thread management overhead may also result from the want to manipulate thread states, context switching, and scheduling at some point of semaphore-based totally thread synchronization. In a few cases, the immoderate utilization of semaphores can affect the utility's typical efficacy and overall performance.
Potential for Starvation:
Thread starvation happens whilst a small quantity of threads is regularly blocked from getting access to shared assets due to inadequately deliberate semaphore utilization. An excessive-priority thread will, as an example, starve decrease-precedence threads if it keeps to accumulate semaphore indicators.
Complexity of Deadlock Avoidance:
Even although semaphores permit you to keep away from deadlocks, designing deadlock-unfastened architectures can be challenging. Careful planning and coordination are vital to ensure that threads accumulate and launch semaphores in the precise collection, with the intention to save you deadlocks.
Difficult to Debug:
It may be tough to identify the basis motive of synchronization troubles that have been delivered because of improper semaphore manipulate. When debugging multi-threaded applications with semaphore-related problems, it could be important to use specialised tools and strategies.