Last active
March 23, 2022 03:34
-
-
Save edimetia3d/02a531bbf7b0e9c83e9e352a735c87fb to your computer and use it in GitHub Desktop.
A lock-free user space "mutex" implemented by std
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <condition_variable> | |
#include <mutex> | |
#include <atomic> | |
/** | |
* A lock-free user space "mutex" implemented by std | |
* | |
* The core idea is very simple: | |
* 1. when there is no contention, we use atomic release/acquire synchronization to do a lock-free lock/unlock. | |
* 2. when there is contention, we use the syscall lock/unlock. | |
* | |
* Note: | |
* cpp20 introduced `wait` `notify_one` `notify_all` to atomic types, it might be better than condition variable. | |
*/ | |
class Futex { | |
private: | |
std::atomic<int> m_counter{0}; | |
std::mutex mutex; | |
std::condition_variable cv; | |
public: | |
void lock() { | |
if (m_counter.fetch_add(1, std::memory_order_acquire) > 0) { | |
std::unique_lock<std::mutex> lock(mutex); | |
// std::cout << "Non-lock-free wait" << std::endl; | |
cv.wait(lock); | |
// std::cout << "Non-lock-free locked" << std::endl; | |
} else { | |
// std::cout << "lock-free locked" << std::endl; | |
} | |
} | |
void unlock() { | |
if (m_counter.fetch_add(-1, std::memory_order_release) == 1) { | |
// std::cout << "lock-free unlocked" << std::endl; | |
} else { | |
std::unique_lock<std::mutex> lock(mutex); | |
cv.notify_one(); | |
// std::cout << "Non-lock-free unlocked" << std::endl; | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment