Created
September 15, 2017 15:51
-
-
Save theuni/554aae8be609d137f958ecb2cda751a4 to your computer and use it in GitHub Desktop.
wallet_load_unload
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 "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