C++ 最佳实践之 M&M rule

C++ 最佳实践之 M&M rule

M&M rule: mutable and metux(or shared_mutex(rwlock) or atomic …) go together!!

首先典型的问题的由来:在设计一个类的时候,我们希望一些方法是 const 的,
然后呢,有些场景,我们又希望所有方法是线程安全,于是使用 shared_mutex 等,
但是 const 方法怎么办 ?不考虑一些 hack的方式,例如 const_cast、直接获取地址等,
— 于是就会使用 mutable 修饰 shared_mutex,这样 const 方法可以正常使用 shared_mutx
的对象的。

另外,

  • 在使用 lambda 表达式(closure)的时候,也可以使用 mutable 修饰,这样通过拷贝方式捕获的变量,也可以在 closure 中修改,但是只是修改了 closure 中的,外面的不受影响!当然如果不用修改,最好是 immutable 的!
  • 然后 C++98 也是可以使用 mutable,例如 gcc、vc 等都是支持的。

Guideline: Remember the “M&M rule”: For a member variable, mutable and mutex (or atomic) go together.

(1) For a member variable, mutable implies mutex (or equivalent): A mutable member variable is presumed to be a mutable shared variable and so must be synchronized internally—protected with a mutex, made atomic, or similar.

(2) For a member variable, mutex (or similar synchronization type) implies mutable: A member variable that is itself of a synchronization type, such as a mutex or a condition variable, naturally wants to be mutable, because you will want to use it in a non-const way (e.g., take a std::lock_guard) inside concurrent const member functions.


See also

console output color

console output color

#


ansi code

  • 终端字符的颜色是用 esc 开头的转义序列进行控制 是文本模式下的系统显示功能
  • esc i.e. \033 (esc ascii 码十进制 27. 八进制 33)
  • 使用 ; 分隔以连续设置
code effect
\033[0m 关闭所有属性
\033[1m 粗体
\033[4m 下划线
\033[5m 闪烁
\033[7m 反显
\033[8m 消隐
\033[22m 非粗体
\033[24m 非下划线
\033[25m 非闪烁
\033[27m 非反显
\033[fg-colorm e.x. \033[30m 设置前景色
\033[bg-colorm e.x. \033[47m 设置背景色
\033[nA 光标上移 n 行
\03[nB 光标下移 n 行
\033[nC 光标右移 n 行
\033[nD 光标左移 n 行
\033[y;xH 设置光标位置 (x, y)
\033[2J 清屏
\033[K 清除从光标到行尾的内容
\033[s 保存光标位置
\033[u 恢复光标位置
\033[?25l 隐藏光标
\033[?25h 显示光标

fg color

  • 字(fg)颜色: [30, 39]
value color
30
31
32 绿
33
34
35
36 深绿
37 白色

bg color

  • 背景(bg)颜色范围: [40, 49]
value color
40
41
42 绿
43
44
45
46 深绿
47 白色

example

#define YUIWONGLOGNFTALL(__name, __fmt, __args...) \
    fprintf(stdout, \
        "\033[30;49m[%s %015ld ALL ][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTFATA(__name, __fmt, __args...) \
    fprintf(stderr, \
        "\033[1;31;49m[%s %015ld FATA][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTERRO(__name, __fmt, __args...) \
    fprintf(stderr, \
        "\033[31;49m[%s %015ld ERRO][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTWARN(__name, __fmt, __args...) \
    fprintf(stderr, \
        "\033[33;49m[%s %015ld WARN][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTNOTE(__name, __fmt, __args...) \
    fprintf(stdout, \
        "\033[1;30;49m[%s %015ld NOTE][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTINFO(__name, __fmt, __args...) \
    fprintf(stdout, \
        "\033[30;49m[%s %015ld INFO][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTDEBU(__name, __fmt, __args...) \
    fprintf(stdout, \
        "\033[36;49m[%s %015ld DEBU][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)
#define YUIWONGLOGNFTDETA(__name, __fmt, __args...) \
    fprintf(stdout, \
        "\033[30;49m[%s %015ld DETA][%s] " __fmt " (%s+%d)\n\033[0m", \
        yuiwong::LogRealTime().c_str(), ::pthread_self(), __name, ##__args, \
        __FILE__, __LINE__)


boost mutex

boost mutex

boost mutex

better use boost::shared_mutex!!
=> see boost::shared_mutex

essentials

  • mutable
  • scoped_lock

boost::mutex example

#include "boost/thread/mutex.hpp" /* mutex* */

class Some {
#define _DOBODIESLOCK() \
    boost::mutex::scoped_lock __lk(this->bodiesLock); \
    (void)(__lk)

    Foo getFoo(void) const
    {
        _DOBODIESLOCK();
        ...
        Foo ret = this->foo:
        ...
        return ret;
    }
    void setFoo(Foo const& foo)
    {
        _DOBODIESLOCK();
        ...
        this->foo = foo;
        ...
    }

    Foo foo;
    mutable boost::mutex bodiesLock;/* !! */
#  undef _DOBODIESLOCK
};

boost shared mutex

essentials

  • mutable
  • shared_lock for read
  • upgrade_lock and upgrade_to_unique_lock for write

example

#include "boost/thread/shared_mutex.hpp" /* shared_mutex */

class Some {
#define _DOSHAREDREAD() \
    boost::shared_lock<boost::shared_mutex> __rLock(this->rwlock); \
    (void)(__rLock)
#define _DOEXCLUSIVEWRITE() \
    boost::upgrade_lock<boost::shared_mutex> __uplock(this->rwlock); \
    boost::upgrade_to_unique_lock<boost::shared_mutex> __wLock(__uplock); \
    (void)(__wLock)

    Foo getFoo(void) const
    {
        _DOSHAREDREAD();
        ...
        Foo ret = this->foo:
        ...
        return ret;
    }
    void setFoo(Foo const& foo)
    {
        _DOEXCLUSIVEWRITE();
        ...
        this->foo = foo;
        ...
    }

    Foo foo;
    mutable boost::shared_mutex rwlock;
#  undef _DOSHAREDREAD
#  undef _DOEXCLUSIVEWRITE
}: