Created
August 6, 2019 09:23
-
-
Save luskan/1f568abf82cff56da4bf549fe425061c to your computer and use it in GitHub Desktop.
Test/profile read/write locking against regular locking
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 <iostream> | |
#include <string> | |
#include <vector> | |
#include <shared_mutex> | |
#include <mutex> | |
#include <thread> | |
#include <map> | |
#include <chrono> | |
#include <future> | |
#include <cassert> | |
using namespace std::chrono_literals; | |
struct Dict { | |
std::map<std::string, std::string> dict; | |
std::mutex m; | |
std::string read(std::string key, std::string def) { | |
std::lock_guard<std::mutex> lk(m); | |
auto it = dict.find(key); | |
return it == dict.end() ? def : it->second; | |
} | |
void write(std::string key, std::string value) { | |
std::lock_guard<std::mutex> lk(m); | |
dict[key] = value; | |
} | |
}; | |
struct RWDict { | |
std::map<std::string, std::string> dict; | |
std::shared_mutex rw_m; | |
std::string read(std::string key, std::string def) { | |
std::shared_lock<std::shared_mutex> lk(rw_m); | |
auto it = dict.find(key); | |
return it == dict.end() ? def : it->second; | |
} | |
void write(std::string key, std::string value) { | |
std::lock_guard<std::shared_mutex> lk(rw_m); | |
dict[key] = value; | |
} | |
}; | |
template<typename D> | |
int ProfileDictCode(int work_load = 100, int read_threads = 5, int write_threads = 2, std::chrono::milliseconds update_wait = 2ms) { | |
D dict; | |
std::vector<std::future<std::string>> futures; | |
std::vector<std::thread> writeThreads; | |
for (int n = 0; n < read_threads; ++n) { | |
std::packaged_task<std::string()> task([&]{ | |
std::string str; | |
for (int k = 0; k < work_load; ++k) { | |
std::string ds; | |
while((ds = dict.read(std::to_string(k), "")) == ""); | |
str += ds; | |
} | |
return str; | |
}); // wrap the function | |
std::future<std::string> f1 = task.get_future(); // get a future | |
futures.emplace_back(std::move(f1)); | |
std::thread t(std::move(task)); // launch on a thread | |
t.detach(); | |
} | |
for (int n = 0; n < write_threads; ++n) { | |
writeThreads.emplace_back(std::thread([&]{ | |
for (int k = 0; k < work_load; ++k) { | |
std::this_thread::sleep_for(update_wait); | |
dict.write(std::to_string(k), std::to_string(k % 10)); | |
} | |
})); | |
} | |
for (auto& t : writeThreads) t.join(); | |
int wholeStrLen = 0; | |
for (auto& f : futures) { | |
f.wait(); | |
wholeStrLen += f.get().size(); | |
} | |
assert(wholeStrLen == work_load*read_threads); | |
return wholeStrLen; | |
} | |
template<typename D> | |
void ProfileAndPring(std::string msg) { | |
using milli = std::chrono::milliseconds; | |
auto start = std::chrono::high_resolution_clock::now(); | |
int wholeStrLen = ProfileDictCode<D>(); | |
auto finish = std::chrono::high_resolution_clock::now(); | |
std::cout << msg | |
<< " : " | |
<< std::chrono::duration_cast<milli>(finish - start).count() | |
<< " ms" | |
<< " and gave result: " | |
<< wholeStrLen | |
<< "\n"; | |
} | |
int main() | |
{ | |
for (int t = 0; t < 5; ++t) { | |
ProfileAndPring<Dict> (std::to_string(t) + "# Regular"); | |
ProfileAndPring<RWDict>(std::to_string(t) + "# Read/Wr"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment