?? ?? ?? ?? 2. write端在写之前,先检查引用计数是否为1,
?? ?? ?? ?? ?? 2.1 如果引用计数为1,则你是数据的唯一拥有者,直接修改。
?? ?? ?? ?? ?? 2.2 如果引用计数大于1,则你不是数据的唯一拥有者,还有其它拥有者,此时数据正在被其它拥有者read,则不能再原来的数据上并发写,应该创建一个副本,并在副本上修改,然后用副本替换以前的数据。这就需要用到一些shared_ptr的编程技法了:
void write()
{
lock()
if(!g_ptr.unique())
{
g_ptr.reset(new Foo(*g_ptr));
}
assert(g_ptr.unique());
//write
//
}?? ?? ?? ?? ?? ?? ??解释一下代码:
?? ?? ?? ?? ?? ?? ?? ?? ??shared_ptr::unique(),当引用计数为1时返回true,否则false。
?? ?? ?? ?? ?? ?? ?? ?? 假设一个线程读,一个线程写,当写线程进入到if循环中时,原对象的引用计数为2,分别为tmpptr和g_ptr,此时reset()函数将原对象的引用计数减1,并且g_ptr已经指向了新的对象(用原对象构造),这样就完成了数据的拷贝,并且原对象还在,只是引用计数变成了1。
?? ?? ?? ?? ?? ?? ?? ?? 注意,reset()函数仅仅只是将原对象的引用计数减1,并没有将原对象析构,当原对象的引用计数为0时才会被析构。

?? ?? 在《Linux多线程服务端编程—使用muduo C++网络库》的2.8节中,按照上面的方法,解决了2.1.1节的NonRecursiveMutex_test例子,在这就不累赘代码了。
??接着讲讲,《Linux多线程服务端编程—使用muduo C++网络库》的2.8节中的三种错误写法。
??错误一:直接修改g_foos所指的 FooList
void post(const Foo& f)
{
MutexLockGuard lock(mutex);
g_foos->push_back(f);
}??如果有别的地方用到g_foos所指的 FooList的某一个迭代器,由于post()函数的push_bak()导致迭代器失效。
??错误二:试图缩小临界区,把copying移出临界区
void post(const Foo& f)
{
FooListPtr newFoos(new FooList(*g_foos));
newFoos->push_back(f);
MutexLockGuard lock(mutex);
g_foos = newFoos;
}??临界区前的两行代码都是线程不安全的。
??程A中,g_foos指向的资源即将被析构(因此递减它所指向资源的引用计数),同时,程B中跑post()函数,正在执行"FooListPtr newFoos(new FooList(*g_foos));"这一行代码,此时正进行拷贝g_foos指向的资源,恐怕会出现core dump。因此要递增同一个引用计数。
void post(const Foo& f)
{
FooListPtr oldFoos;
{
MutexLockGuard lock(mutex);
oldFoos = g_foos;
}
FooListPtr newFoos(new FooList(*oldFoos));
newFoos->push_back(f);
MutexLockGuard lock(mutex);
g_foos = newFoos;
}??新建oldFoos指向原指针,防止被别的线程析构。但在这一行:FooListPtr newFoos(new FooList(*oldFoos)); ,如果有别的线程在修改g_foos所指的 FooList呢,后果可想而知。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-65219-2.html
必将稳步向前
但每个国家都有一些不好的地方
先戳你一下
如果是1937年你肯定是汉奸