When thinking about testability and modular code, I recently thought about wheth
ID: 654278 • Letter: W
Question
When thinking about testability and modular code, I recently thought about whether I should split out the synchronization part of a class from the actual behavior part.
By example:
The app "needs" this:
class Mogrifier { // Mogrifier accesses are thread safe
private:
unsigned int m_state;
mutex m_sync;
public:
Mogrifier()
: m_state(0)
{ }
unsigned int Mutate() {
lock_guard<mutex> lock(m_sync);
const unsigned int old = m_state;
m_state += 42;
return old;
}
:::
};
Seems simple enough, except that locking and the actual stuff the class does aren't really related.
So I though about whether it's a good idea to split this up:
class Mogrifier { // Mogrifier is *not* synchronized
private:
unsigned int m_state;
public:
Mogrifier()
: m_state(0)
{ }
unsigned int Mutate() {
const unsigned int old = m_state;
m_state += 42;
return old;
}
:::
};
class SyncedMogrifer {
private:
mutex m_sync;
Mogrifier m_;
public:
unsigned int Mutate() {
lock_guard<mutex> lock(m_sync);
return m_.Mutate();
}
};
Would you do this?
Will it help with unit testing?
I'm awful with Pattern names ... what is it called?
Is there a simple way to "generate" such a wrapper in C++ for an arbitrary calls?
Explanation / Answer
You really need some assistance from Herb. He can tell you how to deal with this. Cliffnotes:
template<typename T> class Monitor {
T t;
std::mutex m;
public:
template<typename F> auto operator()(F&& f) -> decltype(f(t)) {
lock_guard<mutex> lock(m);
return f(t);
}
};
Monitor<Mogrifier> safe;
safe([](Mogrifier& m) {
m.mutate();
});
The second part is that you really shouldn't block, and if you do, you can't do it on a per-method level.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.