门户网站衰落的原因,wordpress可视化插件下载,桔子建站是什么平台,成都人高清影院品牌加盟死锁是由于不同线程按照不同顺序进行加锁而造成的。如#xff1a; 线程A#xff1a;对lock a加锁 对lock b加锁 dosth 释放lock b 释放lock a 线程B#xff1a;对lock b加锁 对lock a加锁 dosth 释放lock a 释放lock b 这样两条线程… 死锁是由于不同线程按照不同顺序进行加锁而造成的。如 线程A对lock a加锁 对lock b加锁 dosth 释放lock b 释放lock a 线程B对lock b加锁 对lock a加锁 dosth 释放lock a 释放lock b 这样两条线程就可能发生死锁问题。要避免发生死锁应该使用同一个顺序进行加锁。 这点在对象单向调用的情况下是很容易达成的。对象单向调用的意思是如果对象a的函数调用了对象b的函数则对象b中的函数不会去调用对象a的函数注意a和b也可能同属于一个类。 举个例子吧假设聊天室(Room)对象room聊天者(Chatter)对象chatter假设Chatter和Room的定义如下 class InnerChatter { public: void sendMsg(const string msg) { boost::mutex::scoped_lock lock(mtx); socket-send(msg); } private: boost::mutex mtx; TcpSocket socket; }; typedef boost::shared_ptr InnerChatter Chatter; class InnerRoom { public: void sendMsg(const string user, const string msg) { boost::mutex::scoped_lock lock(mtx); if (chatters.find(user) ! chatters.end()) { chatters[user]- sendMsg(user); } } private: boost::mutex mtx; mapstring, Chatter chatters; }; 目前代码中只存在Room调用Chatter的情况不存在Chatter调用RoomRoom调用RoomChatter调用Chatter这三种情况。所以总是先获得room锁再获得chatter锁不会发生死锁。 如果为Chatter加上发送历史和以下这个方法之后呢 vectorstring history; void sendMsgToChatter(Chatter dst, const string msg) { boost::mutex::scoped_lock lock(mtx); // 加锁当前对象 history.push_back(msg); dsgsendMsg(msg); // 注意次函数调用会加锁dst对象 } 乍看起来似乎没问题但如果线程A执行chatterA.sendMsgToChatter(chatterB, “sth”)时线程B正好执行chatterB.sendMsgToChatter(chatterA, “sth”)就会发生本文一开头举例的死锁问题。 如果在Chatter中加入函数 void sendMsgToAll(Room room, const string msg) { boost::mutex::scoped_lock lock(mtx); history.push_back(msg); room-sendMsgToAll(msg); } 在Room中加入函数 void sendMsgToAll(const string msg) { boost::mutex::scoped_lock lock(mtx); for (mapstring, Chatter::iterator it chatters.begin(); it ! chatters.end(); it) { it-second-sendMsg(msg); } } 显然死锁问题更严重了也更令人抓狂了。也许有人要问为什么要这么做不能就保持Room单向调用Chatter吗大部分时候答案是肯定的也建议大部分模块尤其是周边模块如基础设施模块使用明确清晰的单向调用关系这样可以减少对死锁的忧虑少白一些头发。 但有时候保证单向调用的代价太高试想一下如果被调用者b是一个容器类调用者a定义了一些对元素的汇总操作如求和为了避免回调回调打破了单向调用约束那就只有对b加锁复制所有元素解锁遍历求和。复制所有元素比较耗计算资源有可能成为性能瓶颈。 另外还有设计方面的考虑。还举Room和Chatter的例子如果避免Chatter调用Room和Chatter则Chatter很难实现啥高级功能这样所有代码都将堆砌在RoomRoom将成为一个超级类带来维护上的难度。此外还有设计上的不妥因为几乎全部面向对象的设计模式都可以理解成某种方式的回调禁止回调也就禁掉了设计模式可能带来不便。 当对象间的相互调用无法避免时如果只使用传统的mutex保证相同顺序加锁需要十分小心万一编程时失误测试时又没发现这是很可能的死锁很不容易测试出来如果条件允许还可以手忙脚乱地火线gdb若无法调试定位则服务器可能要成为重启帝了对产品的形象十分有害。 我想出的解决方案是既然mutex要保证相同顺序加锁就直接让mutex和一个优先级挂钩使用线程专有存储TSS保存当前线程优先级最低的锁当对新的mutex加锁时如果mutex的优先级 当前优先级为什么不可以参考上文说的sendMsgToChatter函数才允许加锁否则记录当前函数栈信息抛出异常(要仔细设计以免破坏内部数据结构)。代码如下 boost::thread_specific_ptrglobal::stackint locks_hold_by_current_thread; class xrecursive_mutex { public: xrecursive_mutex(int pri_level_) : recursion_count(0) , pri_level(pri_level_){} ~xrecursive_mutex(){} class scoped_lock { public: scoped_lock(xrecursive_mutex mtx_) : mtx(mtx_) { mtx.lock(); } ~scoped_lock() { mtx.unlock(); } private: xrecursive_mutex mtx; }; private: int recursion_count; int pri_level; boost::recursive_mutex mutex; int get_recursion_count() { return recursion_count; } void lock() { mutex.lock(); recursion_count; if (recursion_count 1) { if (locks_hold_by_current_thread.get() NULL) { locks_hold_by_current_thread.reset(new std::stackint()); } if (!locks_hold_by_current_thread-empty() locks_hold_by_current_thread-top() pri_level) { // wrong order, lock failed -- recursion_count; mutex.unlock(); XASSERT(false);//记录栈信息抛异常 } locks_hold_by_current_thread-push(pri_level); } } void unlock() { bool bad_usage_flag false; if (recursion_count 1 locks_hold_by_current_thread.get() ! NULL) { if (!locks_hold_by_current_thread-empty() (locks_hold_by_current_thread-top() pri_level)) { locks_hold_by_current_thread-pop(); } else { bad_usage_flag true; } } -- recursion_count; mutex.unlock(); XASSERT(!bad_usage_flag);// // 记录栈信息抛异常 } }; 使用 xrecursive_mutex mtx1(1); xrecursive_mutex mtx2(2); xrecursive_mutex mtx3(3); xrecursive_mutex mtx3_2(3); { xrecursive_mutex::scoped_lock lock1(mtx1); // pass, 当前线程锁优先级1 xrecursive_mutex::scoped_lock lock2(mtx3); // pass, 当前线程锁优先级3 ASSERT_ANY_THROW(xrecursive_mutex::scoped_lock lock2_2(mtx3_2)); // 捕获异常因为优先级3 当前线程锁优先级 xrecursive_mutex::scoped_lock lock3(mtx3); // pass, 可重入锁 xrecursive_mutex::scoped_lock lock4(mtx1); // pass, 可重入锁 ASSERT_ANY_THROW(xrecursive_mutex::scoped_lock lock5(mtx2)); // 捕获异常因为优先级 2 当前线程锁优先级3 } 来源http://blog.sina.com.cn/s/blog_48d4cf2d0100mx4n.html