关于共同生存周期的对象与锁的讨论

来源:互联网 发布:中银淘宝校园卡毕业后 编辑:程序博客网 时间:2024/06/05 11:02

  之前与同学在谈一道smart pointer的面试题,在实现thread safe的时候发现mutex的destroy始终不好解决。问题在于,当你要destroy的mutex之前,必须先unlock这个mutex,而当你unlock这个mutex的同时,你的destroy部分可能不收保护了。与另外一个同学讨论该问题,告之是锁的设计问题。锁不应该和要锁的对象共享一个生存周期。但是,当我们要实现一个对象一个对象的保护的时候,总不能用一个全局锁去管理吧?后来发现,其实,一个对象一个锁,是可以实现完整的保护的。唯一的问题就是destroy这个对象时候。通过增加一个flag方式,我们还是可以保证destroy也能完美的。

  下面是具体的代码:

class myObj{public:   myObj()    {       pthread_mutex_init(&_mutex);      _isDestroyed = false;   }   ~myObj()   {      pthread_mutex_lock(&_mutex);      _isDestroyed = true;      ... // Do free memory      pthread_mutex_unlock(&_mutex);      pthread_mutex_destroy(&_mutex);   }      void doSomeThing()   {      if (_isDestroyed)         return;      pthread_mutex_lock(&_mutex);      if (_isDestroyed) {         pthread_mutex_unlock(&_mutex);         return;      }      ... // Access critical fields of this object      pthread_mutex_unlock(&_mutex);    }private:   bool _isDestroyed;   pthread_mutex_t _mutex;}

其中,我们引入了一个flag, _isDestroyed这个boolean变量。在析构函数里面,我们一旦准备锁住mutex,马上把这个flag设置成true,表示这个对象即将被destroy。那么,其他函数在访问所有临界资源的时候,首先需要看看,这个对象是否马上要被destroy了。如果是,则退出,什么也不要做了;如果不是,再获取锁。析构函数只可能被调用一次,所以在析构函数里面,我们不用对_isDestroyed做判断。但是,我们需要让_isDestroyed的变量是在mutex lock之后才能设置。

这样,即使有线程在析构函数的pthread_mutex_unlock(&_mutex)和pthread_mutex_destroy(&_mutex)之间执行了doSomeThing,也不会影响到临界资源的破坏。