直接上代码
#include <memory>
#include <iostream>
#include <string.h>
#include <vector>
#include <pthread.h>
using namespace std;
class MutexLock
{
public:
MutexLock()
{
pthread_mutex_init(&_mutex, NULL);
}
~MutexLock()
{
pthread_mutex_destroy(&_mutex);
}
void lock()
{
pthread_mutex_lock(&_mutex);
}
void unlock()
{
pthread_mutex_unlock(&_mutex);
}
pthread_mutex_t * getMutexLockPtr()
{
return &_mutex;
}
private:
pthread_mutex_t _mutex;
};
//RAII
class MutexLockGuard
{
public:
MutexLockGuard(MutexLock & mutex)
: _mutex(mutex)
{
printf("lock\n");
_mutex.lock();
}
~MutexLockGuard()
{
printf("unlock\n");
_mutex.unlock();
}
private:
MutexLock & _mutex;
};
//end of namespace wd
class Observable;
class Observer{
public:
virtual void update() = 0;
};
class Foo : public Observer
{
public:
virtual void update()
{
printf("%ld:Foo::update() %p\n",pthread_self(), this);
}
};
class Observable{
public:
void register_(weak_ptr<Observer> x)
{
observers.push_back(x);
}
void notifyObservers()
{
MutexLockGuard guard(mutex_);
Iterator it = observers.begin();
while(it != observers.end())
{
shared_ptr<Observer> obj(it->lock());
if(obj)
{
obj->update();
}else{
it = observers.erase(it);
}
it++;
}
}
private:
mutable MutexLock mutex_;
vector<weak_ptr<Observer>> observers;
typedef std::vector<weak_ptr<Observer>>::iterator Iterator;
};
Observable subject;
int sum = 10;
void* threadOne(void* arg)
{
int count = 0;
shared_ptr<Foo> foo = make_shared<Foo>();
weak_ptr<Foo> w(foo);
subject.register_(w);
subject.notifyObservers();
}
void* threadTwo(void* arg)
{
int count = 0;
shared_ptr<Foo> foo = make_shared<Foo>();
subject.register_(foo);
subject.notifyObservers();
}
void* threadThree(void* arg)
{
int count = 0;
shared_ptr<Foo> foo = make_shared<Foo>();
// subject.register_(foo);
// subject.notifyObservers();
count++;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_create(&thread1, nullptr,threadOne,nullptr);
pthread_create(&thread2,nullptr,threadTwo,nullptr);
pthread_create(&thread3,nullptr,threadThree,nullptr);
pthread_join(thread1,nullptr);
pthread_join(thread2,nullptr);
pthread_join(thread3,nullptr);
}
其实可以思考这份代码,他是哪里出了问题呢?
根本原因是我的线程没有做时序控制
threadOne
threadTwo
threadThree
这三个函数可能在另一个线程subject.notifyObservers运行完成之前就结束了,所以observers.erase(it)的时候这个对象已经被释放掉了,然后再次对他observers.erase可能core dump就是他最好的归宿了,所以在这种情况下即使加了锁也并不是安全的
扫描二维码关注公众号,回复:
12275369 查看本文章
最后我们用一个例子来说明这个问题
这是一个不正确的例子:
int main()
{
vector<weak_ptr<Foo>> observers;
;
{
shared_ptr<Foo> p(new Foo);
weak_ptr<Foo> f(p);
observers.push_back(f);
}
std::vector<weak_ptr<Foo>>::iterator Iterator = observers.begin();
while(Iterator != observers.end())
{
shared_ptr<Observer> obj(Iterator->lock());
if(obj)
{
obj->update();
}else{
Iterator = observers.erase(Iterator);
}
Iterator++;
}
}
出了作用域之后weak_ptr<Foo> f被释放掉了,出现了
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
但是
int main()
{
vector<weak_ptr<Foo>> observers;
;
{
shared_ptr<Foo> p(new Foo);
weak_ptr<Foo> f(p);
observers.push_back(f);
std::vector<weak_ptr<Foo>>::iterator Iterator = observers.begin();
while(Iterator != observers.end())
{
shared_ptr<Observer> obj(Iterator->lock());
if(obj)
{
obj->update();
}else{
Iterator = observers.erase(Iterator);
}
Iterator++;
}
}
}
如果这样的话就不会出现问题,一切安好,因为没有走出作用域所以weak_ptr没有被释放
/home/zhanglei/ourc/test/cmake-build-debug/test-cpp
140718134794048:Foo::update() 0x55bee3748e70
Process finished with exit code 0
错误原因是我不该给Iterator迭代器++,但是还是出现了coredump 我真的很疑惑 原因再这里
最后又查阅了c++ primer 看到了书中关于erase的介绍
erase 删除迭代器p中的指定元素,返回一个指向被删除元素后的迭代器,如果是末尾则指向off-the-end迭代器
所以在这里如果我们使用了erase 就不要再给迭代器++了
最后我们写一个线程安全的观察者模式
#include <memory>
#include <iostream>
#include <string.h>
#include <vector>
#include <pthread.h>
using namespace std;
class MutexLock
{
public:
MutexLock()
{
pthread_mutex_init(&_mutex, NULL);
}
~MutexLock()
{
pthread_mutex_destroy(&_mutex);
}
void lock()
{
pthread_mutex_lock(&_mutex);
}
void unlock()
{
pthread_mutex_unlock(&_mutex);
}
pthread_mutex_t * getMutexLockPtr()
{
return &_mutex;
}
private:
pthread_mutex_t _mutex;
};
//RAII
class MutexLockGuard
{
public:
MutexLockGuard(MutexLock & mutex)
: _mutex(mutex)
{
_mutex.lock();
}
~MutexLockGuard()
{
_mutex.unlock();
}
private:
MutexLock & _mutex;
};
//end of namespace wd
class Observable;
class Observer{
public:
virtual void update() = 0;
};
class Foo : public Observer
{
public:
virtual void update()
{
printf("%ld:Foo::update() %p\n",pthread_self(), this);
}
};
class Observable{
public:
void register_(weak_ptr<Observer> x)
{
MutexLockGuard guard(mutex_);
observers.push_back(x);
}
void notifyObservers()
{
MutexLockGuard guard(mutex_);
Iterator it = observers.begin();
while(it != observers.end())
{
shared_ptr<Observer> obj(it->lock());
if(obj)
{
obj->update();
it++;
}else{
it = observers.erase(it);
}
}
}
private:
mutable MutexLock mutex_;
vector<weak_ptr<Observer>> observers;
typedef std::vector<weak_ptr<Observer>>::iterator Iterator;
};
Observable subject;
int sum = 10;
void* threadOne(void* arg)
{
shared_ptr<Foo> foo = make_shared<Foo>();
weak_ptr<Foo> w(foo);
subject.register_(w);
subject.notifyObservers();
}
void* threadTwo(void* arg)
{
shared_ptr<Foo> foo = make_shared<Foo>();
subject.register_(foo);
subject.notifyObservers();
}
void* threadThree(void* arg)
{
shared_ptr<Foo> foo = make_shared<Foo>();
subject.register_(foo);
subject.notifyObservers();
}
int main()
{
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_create(&thread1, nullptr,threadOne,nullptr);
pthread_create(&thread2,nullptr,threadTwo,nullptr);
pthread_create(&thread3,nullptr,threadThree,nullptr);
pthread_join(thread1,nullptr);
pthread_join(thread2,nullptr);
pthread_join(thread3,nullptr);
}
注意push_back不是线程安全的,没有锁,可能在register_一半的时候切片到另一个线程,然后造成,vector迭代器不完整,所以也是需要加锁的