Here is a simplified observer pattern:
To implement it, the trick is that observers shall refcnt profile, so the last observer (or creator) can safely destroy it.
I can do it without shared_ptr/weak_ptr, but I wonder if using them can avoid re-inventing wheels.
Here is my code:
#include <iostream>
#include <memory>
#include <thread>
#include <cassert>
volatile bool playing = true;
class Profile {
public:
int a_;
Profile(int v) {a_ = v;}
};
std::shared_ptr<Profile> g_profile{ nullptr };
void observer() {
do {
// observe profile if I can
std::weak_ptr<Profile> weak = g_profile;
if (auto prof = weak.lock()) {
auto a = prof->a_;
// if prof is stable, I shall see the same a_
assert(a == prof->a_);
}
else {
std::cout << ".";
}
} while (playing);
}
void creator() {
do {
// create profile when I start
g_profile.reset(new Profile(std::rand()));
std::weak_ptr<Profile> weak = g_profile;
assert(weak.lock() != nullptr);
// doing some work ...
// destroy profile when I am done
g_profile.reset();
} while (playing);
}
void timer() {
std::this_thread::sleep_for(std::chrono::seconds(10));
playing = false;
}
int main() {
std::thread cr{ creator };
std::thread ob{ observer };
std::thread tm{ timer };
cr.join();ob.join();tm.join();
// no memory leak
}
But the program crashes either at std::weak_ptr<Profile> weak = g_profile
or assert(a == prof->a_)
. So here are my questions:
You have undefined bahavior when one thread reads from the shared pointer g_profile
(observer) while the other thread writes to it (when creator calls std::shared_ptr::reset
)
If you want to use the shared_ptr
from two threads you'll have to use a lock or atomic_shared_ptr
.
Also volatile
does not guarantee any synchronization as it does in java. See this answer .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.