Skip to content

Instantly share code, notes, and snippets.

@theuni
Created September 15, 2017 15:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theuni/554aae8be609d137f958ecb2cda751a4 to your computer and use it in GitHub Desktop.
Save theuni/554aae8be609d137f958ecb2cda751a4 to your computer and use it in GitHub Desktop.
wallet_load_unload
#include "strong_ptr.h"
#include <cassert>
#include <chrono>
#include <cstdio>
#include <mutex>
#include <thread>
#include <vector>
namespace {
class CWallet
{
public:
explicit constexpr CWallet(int id) : m_id(id){}
int get_id() const { return m_id; }
int32_t get_balance() const { return m_balance; }
void set_balance(int32_t balance) { m_balance = balance; }
private:
const int m_id;
int32_t m_balance{0};
};
std::mutex g_wallet_mutex;
std::vector<strong_ptr<CWallet>> g_wallets;
std::weak_ptr<CWallet> load_wallet(int id)
{
// read/load from disk
auto strong = make_strong<CWallet>(id);
std::weak_ptr<CWallet> ret(strong.get_shared());
// Do not add to the global vector until fully loaded. At that point, it's
// safe to access
{
std::lock_guard<std::mutex> lock(g_wallet_mutex);
g_wallets.push_back(std::move(strong));
printf("loaded wallet: %i\n", id);
}
return ret;
}
void unload_wallet(int id)
{
// Move the wallet out of the global vector first, so that other threads can
// no longer access it. Then unload it once we have unique access
decay_ptr<CWallet> decaying;
{
std::lock_guard<std::mutex> lock(g_wallet_mutex);
for (auto it = g_wallets.begin(); it != g_wallets.end(); ++it) {
if ((*it)->get_id() == id) {
decaying = std::move(*it);
g_wallets.erase(it);
break;
}
}
}
if (decaying) {
while (!decaying.decayed()) {
// TODO: decay_ptr needs a wait_for_decay().
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
printf("unloading wallet: %i\n", decaying->get_id());
}
}
std::weak_ptr<CWallet> use_wallet(int id)
{
std::weak_ptr<CWallet> ret;
{
std::lock_guard<std::mutex> lock(g_wallet_mutex);
for (const auto& wallet : g_wallets) {
if (wallet->get_id() == id) {
ret = wallet.get_shared();
break;
}
}
}
if (ret.expired()) {
ret = load_wallet(id);
}
return ret;
}
void show_wallet_balance(int id)
{
if (auto wallet = use_wallet(id).lock()) {
printf("balance for wallet %i is: %i\n", id, wallet->get_balance());
} else {
printf("wallet not loaded: %i\n", id);
};
}
} // namespace
int main()
{
for (int i = 0; i < 10; i++) {
if (auto wallet = load_wallet(i).lock()) {
wallet->set_balance(i);
}
}
for (int i = 0; i < 10; i++) {
std::thread([i]{
show_wallet_balance(i);
}).detach();
}
// balance printing may or may not complete for each wallet, but they will never unload while
// another thread has access
for (int i = 0; i < 10; i++) {
unload_wallet(i);
}
std::lock_guard<std::mutex> lock(g_wallet_mutex);
assert(g_wallets.empty());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment