Controlul Accesului la Resurse Limitate cu std::counting_semaphore în C++20 în C++

Ghid practic pentru semafoarele moderne în C++20: limitarea accesului concurent la un număr fix de resurse partajate (thread pool-uri, pool-uri de conexiuni la baze de date) prin std::counting_semaphore și std::binary_semaphore.

Sintaxă
#include <semaphore> | std::counting_semaphore<8> pool(8); pool.acquire(); pool.release();

Spre deosebire de un std::mutex (care permite accesul unui singur thread la un moment dat și impune ca thread-ul care blochează mutex-ul să fie exact cel care îl deblochează), un semafor este o primitivă de semnalizare care gestionează un număr de autorizații (permits) disponibile. Introdus în C++20 prin header-ul <semaphore>, std::counting_semaphore este soluția nativă ideală pentru a limita concurența la un bazin finit de resurse (de exemplu, maximum 5 conexiuni concurente la baza de date sau un număr fix de sloturi de procesare GPU).

Gestionarea unui pool de 3 conexiuni concurente
#include <semaphore>
#include <thread>
#include <vector>
#include <chrono>
#include <print>

// Permitem maximum 3 conexiuni concurente:
std::counting_semaphore<3> sloturiConexiuni(3);

void acceseazaBazaDate(int workerId) {
    // Solicită un slot liber (blochează dacă toate cele 3 sloturi sunt ocupate):
    sloturiConexiuni.acquire();

    std::println("Worker-ul {} a obtinut conexiunea. Executa tranzactie...", workerId);
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::println("Worker-ul {} a terminat. Elibereaza conexiunea.", workerId);

    // Eliberează slotul pentru următorul worker din coadă:
    sloturiConexiuni.release();
}

int main() {
    std::vector<std::jthread> threaduri;
    for (int i = 1; i <= 8; ++i) {
        threaduri.emplace_back(acceseazaBazaDate, i);
    }
    return 0;
}