其实这个bug并不发生在:
当UI主线程使用strLog中的字符串更新Edit,
同时AddText被其他线程调用进行m_strStore +=操作
这种情况,
而是发生在:
当UI主线程调用strLog中的析构函数,
同时AddText被其他线程调用进行m_strStore +=操作
这种时候。
为什么会发生这种情况了?
首先我们看当UI主线程调用strLog中的析构函数的情况:
大概的程序流程是:
a1. 检查引用计数是否大于1
a2. 是, 引用计数减一,返回
a3. 否则,释放字符串
注意,1-2步并不是一个原子操作,而且读取引用计数的时候并没有临界端保护。
然后我们再看AddText被其他线程调用进行m_strStore +=操作 时发生的情况
b1. 判断引用计数是否大于1
b2. 是,引用计数减一,分配新字符串并指向之
b3. 否,在当前字符串继承上进行+=操作,如果空间不够,可能也要重新分配字符串。
同样,1-2步并不是一个原子操作,而且读取引用计数的时候并没有临界端保护。
这样考虑如下的执行序列:
a1, //发现引用计数为2
b1 //发现引用计数为2
b2 //引用计数减一,分配新字符串并指向之
a2 //引用计数减一,返回
在执行完b2的时候,引用计数已经为1了,但a线程接下来运行a2的时候,引用计数再次减一,变为0。同时,这块内存已经成为”孤魂野鬼“,不在被任何一个std::string对象所拥有,造成内存泄漏。
我们现在发现了问题,那么如何改正这个错误呢?