-
Notifications
You must be signed in to change notification settings - Fork 7
named_semaphore.hpp
Not Enough Standards' named semaphores are defined in header <nes/named_semaphore.hpp>
Named semaphores are synchronization primitives that use a resource counter. When trying to acquire a resource, the calling thread is blocked until a resource is available.
Named semaphores can be shared among multiple processes. A named semaphore is accessed using its name. On construction, it will create a new, or open an existing, named semaphore.
nes::named_semaphore
is the default named semaphore implementation. A resource of nes::semaphore
can be acquired or release. You can also try to acquire a resource, in order to prevent the calling thread from waiting if no resource is available.
nes::timed_named_semaphore
provide the same interface as nes::named_semaphore
, plus two functions. One of them tries to acquire a resource in a certain delay, when the other tries to acquire it until a specific time point is reached.
namespace nes
{
static constexpr const char named_semaphore_root[] = /*implementation_defined*/;
class named_semaphore
{
public:
using native_handle_type = /*implementation_defined*/;
public:
explicit named_semaphore(const std::string& name, std::size_t initial_count = 0);
~named_semaphore();
named_semaphore(const named_semaphore&) = delete;
named_semaphore& operator=(const named_semaphore&) = delete;
named_semaphore(named_semaphore&& other) noexcept = delete;
named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
void acquire();
bool try_acquire();
void release();
native_handle_type native_handle() const noexcept;
};
class timed_named_semaphore
{
public:
using native_handle_type = /*implementation_defined*/;
public:
explicit timed_named_semaphore(const std::string& name, std::size_t initial_count = 0);
~timed_named_semaphore();
timed_named_semaphore(const timed_named_semaphore&) = delete;
timed_named_semaphore& operator=(const timed_named_semaphore&) = delete;
timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
timed_named_semaphore& operator=(timed_named_semaphore&& other) noexcept = delete;
void acquire();
bool try_acquire();
template<class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout);
template<class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& time_point);
void release();
native_handle_type native_handle() const noexcept;
};
}
Here is an example in which we can see cross-process semaphore usage.
main.cpp
is the main file of the parent process.
other.cpp
is the main file of the child process.
Possible output
is the standard output of the parent process.
#include <thread>
#include <iostream>
#include <nes/process.hpp>
#include <nes/named_semaphore.hpp>
int main()
{
//Create a new named semaphore, named "nes_example_named_semaphore"
nes::named_semaphore semaphore{"nes_example_named_semaphore"};
//Create the other process
nes::process other{other_path, nes::process_options::grab_stdout};
for(std::size_t i{}; i < 8; ++i)
{
//Wait before releasing a resource
std::this_thread::sleep_for(std::chrono::milliseconds{100});
//Increment the resource counter
semaphore.release();
}
//Read the entire standard output of the child process. (nes::process_options::grab_stdout must be specified on process creation)
std::cout << other.stdout_stream().rdbuf() << std::endl;
if(other.joinable())
other.join();
}
#include <chrono>
#include <iostream>
#include <nes/named_semaphore.hpp>
int main()
{
//Open the named semaphore
nes::named_semaphore semaphore{"nes_example_named_semaphore"};
const auto tp1{std::chrono::high_resolution_clock::now()};
for(std::size_t i{}; i < 8; ++i)
{
//Wait for a resource
semaphore.acquire();
//Display how long we have waited
const auto elapsed_time{std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - tp1)};
std::cout << "Acquired after " << elapsed_time.count() << "ms." << std::endl;
}
}
Acquired after 96ms.
Acquired after 196ms.
Acquired after 297ms.
Acquired after 398ms.
Acquired after 498ms.
Acquired after 599ms.
Acquired after 700ms.
Acquired after 800ms.