loulett

futex

May 24th, 2016
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.61 KB | None | 0 0
  1. #include <thread>
  2. #include <mutex>
  3. #include <chrono>
  4. #include <random>
  5. #include <vector>
  6. #include <iostream>
  7. #include <exception>
  8. #include <atomic>
  9. #include <numeric>
  10.  
  11. using namespace std::chrono_literals;
  12.  
  13. class futex {
  14. public:
  15.     futex() : is_locked(false) {}
  16.     void lock();
  17.     bool try_lock();
  18.     void unlock();
  19. private:
  20.     std::atomic_bool is_locked;
  21.     bool a = false;
  22. };
  23.  
  24. void futex::lock() {
  25.     a = false;
  26.     if (!is_locked.compare_exchange_strong(a, true))
  27.         throw std::exception("Try to lock locked futex");
  28. }
  29.  
  30. bool futex::try_lock() {
  31.     a = false;
  32.     return is_locked.compare_exchange_strong(a, true);
  33. }
  34.  
  35. void futex::unlock() {
  36.     a = true;
  37.     if (!is_locked.compare_exchange_strong(a, false))
  38.         throw std::exception("Try to unlock unlocked futex");
  39. }
  40.  
  41. int variable_to_change = 0;
  42. futex my_futex;
  43. std::mutex my_mutex;
  44.  
  45. void job1() {
  46.     while(!my_futex.try_lock()) {
  47.         std::this_thread::sleep_for(2s);
  48.     }
  49.     variable_to_change++;
  50.     my_futex.unlock();
  51. }
  52.  
  53. void job2() {
  54.     while (!my_mutex.try_lock()) {
  55.         std::this_thread::sleep_for(2s);
  56.     }
  57.     variable_to_change++;
  58.     my_mutex.unlock();
  59. }
  60.  
  61. int main() {
  62.     std::vector<std::thread> threads1;
  63.     std::vector<std::thread> threads2;
  64.     std::chrono::steady_clock::time_point start, end;
  65.  
  66.     start = std::chrono::steady_clock::now();
  67.     for (int i = 0; i < std::thread::hardware_concurrency() / 2; i++) {
  68.         threads1.push_back(std::thread(job1));
  69.     }
  70.     end = std::chrono::steady_clock::now();
  71.     std::cout << (end - start).count() << std::endl;
  72.  
  73.     start = std::chrono::steady_clock::now();
  74.     for (int i = 0; i < std::thread::hardware_concurrency() * 2; i++) {
  75.         threads2.push_back(std::thread(job2));
  76.     }
  77.     end = std::chrono::steady_clock::now();
  78.  
  79.     std::cout << (end - start).count() << std::endl;
  80.  
  81.     for (auto&& t : threads1)
  82.         t.join();
  83.     for (auto&& t : threads2)
  84.         t.join();
  85.     return 0;
  86. }
  87.  
  88. // при запуске с количеством потоков std::thread::hardware_concurrency() / 2 время 70866807, 1055308 для фьютекса и мьютекса соответсвенно
  89. // при запуске с количеством потоков std::thread::hardware_concurrency() * 2 время 4044944, 8354921 для фьютекса и мьютекса соответсвенно
  90. // Возможно, это связано с устройством мьютекса, т.е. внутри мьютекса вызовы устроены так, что для потоков, количество которых не превосходит std::thread::hardware_concurrency(), использование мьютекса оптимально, например.
Advertisement
Add Comment
Please, Sign In to add comment