Created
February 3, 2017 02:39
-
-
Save dymk/7a4cb61405207ce857a70241ec97b572 to your computer and use it in GitHub Desktop.
clang++-3.8 --std=c++14 rw_tx_lock.cc
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 <chrono> | |
| #include <thread> | |
| #include <mutex> | |
| #include <atomic> | |
| #include <utility> | |
| #include <thread> | |
| #include <memory> | |
| #include <string> | |
| #include <iostream> | |
| template <typename T> | |
| class rw_tx_lock { | |
| std::shared_ptr<T> local_t; | |
| std::mutex obj_lock; // synchronize the entire object | |
| std::mutex writer_lock; // only allow one writer at a time | |
| public: | |
| template <typename... Args> | |
| rw_tx_lock(Args&&... args) { | |
| local_t = std::make_shared<T>(std::forward<Args>(args)...); | |
| } | |
| std::shared_ptr<const T> get_readable() { | |
| std::lock_guard<std::mutex> l(this->obj_lock); | |
| return local_t; | |
| } | |
| template <typename Cb> | |
| void get_writeable(Cb const& cb) { | |
| std::lock_guard<std::mutex> l(writer_lock); // only one writer at a time | |
| auto readable = this->get_readable(); | |
| std::shared_ptr<T> new_local_t = cb(readable); | |
| std::lock_guard<std::mutex> rl(obj_lock); // serialize access to local_t | |
| this->local_t = new_local_t; | |
| } | |
| }; | |
| struct Foo { | |
| int local; | |
| Foo(int local) : local(local) {} | |
| }; | |
| std::mutex cout_mtx; | |
| void rand_sleep() { | |
| auto const min = 100; | |
| auto const max = 300; | |
| int rand_ms = rand()%(max-min + 1) + min; | |
| std::this_thread::sleep_for(std::chrono::milliseconds(rand_ms)); | |
| } | |
| int main() { | |
| rw_tx_lock<Foo> foo_transactor(0); | |
| auto reader_routine = [&foo_transactor](int tid) { | |
| // release lock on readable twice | |
| for(int j = 0; j < 2; j++) { | |
| auto readable = foo_transactor.get_readable(); | |
| for(int i = 0; i < 3; i++) { | |
| { | |
| std::lock_guard<std::mutex> l(cout_mtx); | |
| std::cout << "thread " << tid << " read value: " << readable->local << std::endl; | |
| } | |
| // does not compile :) readable is a `const Foo` | |
| // readable->local += 1 | |
| rand_sleep(); | |
| } | |
| } | |
| }; | |
| auto writer_routine = [&foo_transactor](int tid) { | |
| for(int i = 0; i < 3; i++) { | |
| foo_transactor.get_writeable([&](auto const& old) { | |
| // also does not compile | |
| // old->local += 1; | |
| { | |
| std::lock_guard<std::mutex> l(cout_mtx); | |
| std::cout << "thread " << tid << " write value: " << old->local << std::endl; | |
| } | |
| return std::make_shared<Foo>(old->local + 1); | |
| }); | |
| rand_sleep(); | |
| } | |
| }; | |
| std::thread t0(reader_routine, 0); | |
| std::thread t1(reader_routine, 1); | |
| std::thread t2(reader_routine, 2); | |
| std::thread t3(writer_routine, 3); | |
| std::thread t4(writer_routine, 4); | |
| t0.join(); | |
| t1.join(); | |
| t2.join(); | |
| t3.join(); | |
| t4.join(); | |
| std::cout << "final value: " << foo_transactor.get_readable()->local << std::endl; | |
| return 0; | |
| } | |
| // thread 0 read value: 0 | |
| // thread 2 read value: 0 | |
| // thread 1 read value: 0 | |
| // thread 3 write value: 0 | |
| // thread 4 write value: 1 | |
| // thread 3 write value: 2 | |
| // thread 4 write value: 3 | |
| // thread 2 read value: 0 | |
| // thread 0 read value: 0 | |
| // thread 1 read value: 0 | |
| // thread 3 write value: 4 | |
| // thread 4 write value: 5 | |
| // thread 2 read value: 0 | |
| // thread 1 read value: 0 | |
| // thread 0 read value: 0 | |
| // thread 2 read value: 6 | |
| // thread 0 read value: 6 | |
| // thread 1 read value: 6 | |
| // thread 1 read value: 6 | |
| // thread 0 read value: 6 | |
| // thread 2 read value: 6 | |
| // thread 1 read value: 6 | |
| // thread 0 read value: 6 | |
| // thread 2 read value: 6 | |
| // final value: 6 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment