Skip to content

Instantly share code, notes, and snippets.

@luskan
Created August 6, 2019 09:23
Show Gist options
  • Save luskan/1f568abf82cff56da4bf549fe425061c to your computer and use it in GitHub Desktop.
Save luskan/1f568abf82cff56da4bf549fe425061c to your computer and use it in GitHub Desktop.
Test/profile read/write locking against regular locking
#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