home | help
std::counti...re::acquire(3)   C++ Standard Libary  std::counti...re::acquire(3)

NAME
     std::counting_semaphore::acquire - std::counting_semaphore::acquire

Synopsis
	void acquire();  (since C++20)

	Atomically decrements the internal counter by 1 if it is greater than 0;
     otherwise
	blocks until it is greater than 0 and can successfully decrement the in-
     ternal
	counter.

Preconditions
	(none)

Parameters
	(none)

Exceptions
	May throw std::system_error.

Example
	The  example  visualizes a concurrent work of several randomized threads
     when no more
	than N (N is the semaphore desired value) of  the  thread-functions  are
     active, while
	the other might wait on the semaphore.

     // Run this code

      #include <array>
      #include <chrono>
      #include <cstddef>
      #include <iomanip>
      #include <iostream>
      #include <mutex>
      #include <new>
      #include <random>
      #include <semaphore>
      #include <thread>
      #include <vector>

      using namespace std::literals;

      constexpr std::size_t max_threads{10U}; // change and see the effect
      constexpr std::ptrdiff_t max_sema_threads{3}; // {1} for binary semaphore
      std::counting_semaphore semaphore{max_sema_threads};
      constexpr auto time_tick{10ms};

      unsigned rnd()
      {
	  static  std::uniform_int_distribution<unsigned>  distribution{2U, 9U};
     // [delays]
	  static std::random_device engine;
	  static std::mt19937 noise{engine()};
	  return distribution(noise);
      }

      class alignas(std::hardware_destructive_interference_size) Guide
      {
	  inline static std::mutex cout_mutex;
	  inline    static     std::chrono::time_point<std::chrono::high_resolu-
     tion_clock> started_at;
	  unsigned delay{rnd()}, occupy{rnd()}, wait_on_sema{};

      public:
	  static  void	start_time()  {  started_at  = std::chrono::high_resolu-
     tion_clock::now(); }

	  void initial_delay() { std::this_thread::sleep_for(delay * time_tick);
     }

	  void occupy_sema()
	  {
	      wait_on_sema =
		  static_cast<unsigned>(std::chrono::dura-
     tion_cast<std::chrono::milliseconds>(
		      std::chrono::high_resolution_clock::now() - started_at -
		      delay * time_tick).count() / time_tick.count());
	      std::this_thread::sleep_for(occupy * time_tick);
	  }

	  void visualize(unsigned id, unsigned x_scale = 2) const
	  {
	      auto cout_n = [=](auto str, unsigned n)
	      {
		  for (n *= x_scale; n-- > 0; std::cout << str)
		      ;
	      };
	      std::lock_guard lk{cout_mutex};
	      std::cout << '#' << std::setw(2) << id << ' ';
	      cout_n("a", delay);
	      cout_n("a", wait_on_sema);
	      cout_n("a", occupy);
	      std::cout << '\n';
	  }

	  static void show_info()
	  {
	      std::cout << "\nThreads: " << max_threads << ", Throughput:  "  <<
     max_sema_threads
			<<  "  a Legend: initial delay aa a wait state aa a sema
     occupation aa \n"
			<< std::endl;
	  }
      };

      std::array<Guide, max_threads> guides;

      void workerThread(unsigned id)
      {
	  guides[id].initial_delay(); // emulate some work before sema	acquisi-
     tion
	  semaphore.acquire();	       //  wait until a free sema slot is avail-
     able
	  guides[id].occupy_sema();   // emulate some work  while  sema  is  ac-
     quired
	  semaphore.release();
	  guides[id].visualize(id);
      }

      int main()
      {
	  std::vector<std::jthread> threads;
	  threads.reserve(max_threads);

	  Guide::show_info();
	  Guide::start_time();

	  for (auto id{0U}; id != max_threads; ++id)
	      threads.push_back(std::jthread(workerThread, id));
      }

Possible output:
      Default case: max_threads{10U}, max_sema_threads{3}

      Threads:	10,  Throughput:  3 a Legend: initial delay aa a wait state aa a
     sema occupation aa

      # 1 aaaaaaaaaa
      # 2 aaaaaaaaaaaa
      # 5 aaaaaaaaaaaaaaaa
      # 8 aaaaaaaaaaaaaaaaaaaaaaaa
      # 9 aaaaaaaaaaaaaaaaaaaaaaaaaa
      # 7 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 4 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 6 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      "Enough  for  everyone"  case   (no   wait   states!):   max_threads{10U},
     max_sema_threads{10}

      Threads:	10,  Throughput: 10 a Legend: initial delay aa a wait state aa a
     sema occupation aa

      # 4 aaaaaaaaaa
      # 5 aaaaaaaaaa
      # 3 aaaaaaaaaaaaaa
      # 1 aaaaaaaaaaaaaa
      # 8 aaaaaaaaaaaaaaaaaaaa
      # 6 aaaaaaaaaaaaaaaaaaaaaa
      # 7 aaaaaaaaaaaaaaaaaaaaaa
      # 9 aaaaaaaaaaaaaaaaaaaaaaaaaa
      # 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      Binary semaphore case: max_threads{10U}, max_sema_threads{1}

      Threads: 10, Throughput: 1 a Legend: initial delay aa a wait  state  aa  a
     sema occupation aa

      # 6 aaaaaaaa
      # 5 aaaaaaaaaaaa
      # 4 aaaaaaaaaaaaaaaaaaaaaa
      # 7 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 								       0
     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 								       1
     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 								       8
     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      # 								       9
     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

See also
	release 	  increments the internal counter and unblocks acquirers
			  (public member function)
	try_acquire	  tries to decrement the internal counter without block-
     ing
			  (public member function)
			  tries  to decrement the internal counter, blocking for
     up to a
	try_acquire_for   duration time
			  (public member function)
			  tries to decrement the internal counter, blocking  un-
     til a point in
	try_acquire_until time
			  (public member function)

http://cppreference.com 	   2024.06.10	    std::counti...re::acquire(3)

home | help