Non-blocking semaphores in C ++ 11?

Several questions on this site are related to the lack of a semaphore object in multi-threaded support introduced in C ++ 11. Many have suggested implementing semaphores using mutexes or variable conditions, or a combination of both .

However, none of these approaches allows you to increase and decrease the semaphore, ensuring that the calling thread is not blocked, since it is usually necessary to obtain a lock before writing the semaphore value. The POSIX semaphore, for example, has the functions sem_post() and sem_trywait() , both of which are not blocked.

Is it possible to implement a non-blocking semaphore with support for C ++ 11 multithreading? Or should I definitely use an OS-specific library for this? If so, why does C ++ 11 not include a semaphore object?

A similar question was not received after 3 years. (Note: I believe that the question I ask is much wider, although, of course, there are other uses for the non-blocking semaphore object other than the producer / consumer. If, despite this, someone believes that my question is a duplicate, then please tell me how I can pay attention to the old question, since it still remains open.)

+5
source share
1 answer

I do not see a problem for implementing the semaphore. Using atomicity and C ++ 11 mutexes should be possible.

 class Semaphore { private: std::atomic<int> count_; public: Semaphore() : count_(0) // Initialized as locked. { } void notify() { count_++; } void wait() { while(!try_wait()) { //Spin Locking } } bool try_wait() { int count = count_; if(count) { return count_.compare_exchange_strong(count, count - 1); } else { return false; } } }; 

Here is a small usage example:

 #include <iostream> #include "Semaphore.hpp" #include <thread> #include <vector> Semaphore sem; int counter; void run(int threadIdx) { while(!sem.try_wait()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } //Alternative use wait //sem.wait() std::cout << "Thread " << threadIdx << " enter critical section" << std::endl; counter++; std::cout << "Thread " << threadIdx << " incresed counter to " << counter << std::endl; // Do work; std::this_thread::sleep_for(std::chrono::milliseconds(30)); std::cout << "Thread " << threadIdx << " leave critical section" << std::endl; sem.notify(); } int main() { std::vector<std::thread> threads; for(int i = 0; i < 15; i++) { threads.push_back(std::thread(run, i)); } sem.notify(); for(auto& t : threads) { t.join(); } std::cout << "Terminate main." << std::endl; return 0; } 

Of course, waiting is a blocking operation. But notify and try_wait are not blocking if the comparison and exchange operation is not blocked (can be checked).

+3
source

Source: https://habr.com/ru/post/1264291/


All Articles