рд╕рдВрднрд╛рд╡рд┐рдд рдЧрддрд┐рд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдЧрддрд┐рд╢реАрд▓ рдЦреЛрдЬ

рдирдорд╕реНрддреЗ рдХреБрдЫ рд╕рдордп рдкрд╣рд▓реЗ рдореИрдВрдиреЗ рдПрдХ рдирд╣реАрдВ рдмрд▓реНрдХрд┐ рдмрдбрд╝реЗ рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рдЙрддреНрдкрд╛рдж рдХреЗ рд░рдЦрд░рдЦрд╛рд╡ рдореЗрдВ рд╕рдВрд▓рдЧреНрди рд╣реЛрдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рд╕рдВрдкрд╛рджрди рдХреЗ рдмрд╛рдж рд╕рдВрдкрд╛рджрди рдФрд░ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ, рдЧрддрд┐рд░реЛрдз рдореЗрд░реЗ рдКрдкрд░ рдЖ рдЧрдпрд╛ред рдореИрдВрдиреЗ рдЬрд▓реНрджреА рд╕реЗ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕реНрд░реЛрдд рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ - рдпреЗ рдиреЗрд╕реНрдЯреЗрдб рддрд╛рд▓реЗ рд╣реИрдВ ред рдПрдХ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдЙрддреНрдкрд╛рдж рдХреА рдмреБрдирд┐рдпрд╛рджреА рдмрд╛рддреЛрдВ рдХреА рдЕрдЬреНрдЮрд╛рдирддрд╛ рд╕реЗ, рдореИрдВрдиреЗ рдШреЛрдВрд╕рд▓реЗ рдХреЗ рддрд╛рд▓реЗ рдХреЗ рдЖрджреЗрд╢ рдХрд╛ рдЙрд▓реНрд▓рдВрдШрди рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рд╕реНрд░реЛрдд рдХреЛ рдЦреЛрдЬрдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓ рд░рд╣рд╛ред

Borjomi рдкреАрдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрд░ рд╣реЛ рдЪреБрдХреА рд╣реИ, рдпрд╣ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд▓рд╛рдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИред рд╣рдо рднрд╛рд░реА рддреЛрдкрдЦрд╛рдиреЗ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред


рддреЛ, рдХреНрд▓рд╛рд╕рд┐рдХ рд╕рдорд╕реНрдпрд╛ (рдЫрджреНрдо рдХреЛрдб):
object m1; object m2; // thread 1 quard<> g1(m1); .... //   m2  thread 2 quard<> g2(m2); // thread 2 quard<> g2(m2); .... //   m2  thread 1 quard<> g1(m1); 

рдпрджрд┐ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдПрдХ рд╕рд╛рде рдпрд╛ рдЙрд╕реА рдХреНрд░рдо рдореЗрдВ рдЕрд╡рд░реБрджреНрдз рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реЛрддрд╛, рддреЛ рдЧрддрд┐рд░реЛрдз рдЙрддреНрдкрдиреНрди рдирд╣реАрдВ рд╣реЛрддрд╛ред

рдЖрдЗрдбрд┐рдпрд╛ред


рдмреНрд▓реЙрдХрд░ рдХреНрд▓рд╛рд╕ рдХреЛ рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реЙрдХ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдХрд╛ рдПрдХ рдЧреНрд░рд╛рдл рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдЬрдм рдЕрдЧрд▓реЗ рд╕рдореНрдорд┐рд▓рди рдкрд░ рдЪрдХреНрд░реАрдп рд▓рд┐рдВрдХ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдпрд╣ рд╡рд╛рдВрдЫрд┐рдд рд╕рдВрднрд╛рд╡рд┐рдд рдЧрддрд┐рд░реЛрдз рд╣реЛрдЧрд╛ред
рдПрдХ рдЙрджрд╛рд╣рд░рдг:
рд╕реНрдЯреНрд░реАрдо рдХреЛрдб рдореЗрдВ рдХрд╣реАрдВ: рдЧрд╛рд░реНрдб (рдПрдо 1) -> рдЧрд╛рд░реНрдб (рдПрдо 2)
рд╕реНрдЯреНрд░реАрдо рдХреЛрдб рдореЗрдВ рдХрд╣реАрдВ: рдЧрд╛рд░реНрдб (рдПрдо 2) -> рдЧрд╛рд░реНрдб (рдПрдо 1) !!! рдЕрд▓рд╛рд░реНрдо !!! рдкрд░рд┐рдкрддреНрд░ рд▓рд┐рдВрдХ рдХрд╛ рдкрддрд╛ рдЪрд▓рд╛ред

рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рдЕрдкрдиреЗ рдЖрдк рдХреЛ рд░реЗрдЦрд╛рдВрдХрди рдХрд░рдирд╛ рдХрдард┐рди рд╣реИред рдореИрдВрдиреЗ рдмреВрд╕реНрдЯ / рдЧреНрд░рд╛рдл рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ред
рдбреАрдПрд▓рдПрд▓ рдореЙрдбреНрдпреВрд▓ рдХреЗ рдкреНрд░рд╡рд╛рд╣ рдореЗрдВ рдЕрд╡рд░реЛрдз рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдирд╛ - "рдмреВрд╕реНрдЯ / рдЗрдВрдЯрд░рдкреНрд░реЛрд╕реЗрд╕"ред
рдпрд╣ рдЖрдВрддрд░рд┐рдХ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЛ рдкреЗрдВрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИред рдХреБрдЫ рдореБрдЦреНрдп рдмрд┐рдВрджреБ:

рдЙрдкрдпреЛрдЧ рддреБрдЪреНрдЫ рд╣реИ:
 #define ENABLE_DEADLOCK_CHECKER /**/ #include "deadlock_checker.h" static deadlock_checker_main_t deadlock_checker_main; /*  */ class guard { guard() { deadlock_checker_t::push(this); } ~guard() { deadlock_checker_t::pop(this); } }; 


рдкреБрдирд╢реНрдЪ рд╕рдм рдХреБрдЫ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ред рдореИрдВрдиреЗ рдЧрддрд┐рд░реЛрдз рдкрдХрдбрд╝рд╛ред рдореИрдВ рдЗрд╕ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдЙрддреНрдкрд╛рдж рдХреЗ рддрд╛рдУ рдХреЛ рдЬрд╛рдирддрд╛ рдерд╛ рдФрд░ рдмреЗрдХрд╛рд░ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЙрдбреНрдпреВрд▓ рдХреЛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рдерд╛ред

рдХрд╛рд░реНрдп рдХреЛрдб
 /* *    - . */ #pragma once #include <assert.h> #include <stack> #include <map> #include <vector> #include <boost/thread/mutex.hpp> #include <boost/thread/tss.hpp> #include <boost/thread/once.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/visitors.hpp> #include <boost/filesystem.hpp> #include <boost/interprocess/managed_shared_memory.hpp> #ifdef _DEBUG //#define ENABLE_DEADLOCK_CHECKER #endif namespace deadlock_checker { inline unsigned long get_current_process_id() { return GetCurrentProcessId(); } /**  */ template<typename T> struct deadlock_graph_i { /**   * @return true     */ virtual bool _cdecl insert(const void* locker_child, const void* locker_root) = 0; }; /**  */ template<typename T> class deadlock_graph : public deadlock_graph_i<T> { struct cycle_detector : public ::boost::dfs_visitor<> { cycle_detector(bool& has_cycle) : m_has_cycle(has_cycle) { } template <class Edge, class Graph> void back_edge(Edge, Graph&) { m_has_cycle = true; } protected: bool& m_has_cycle; }; typedef ::boost::adjacency_list<::boost::mapS, ::boost::mapS, ::boost::bidirectionalS, ::boost::property<::boost::vertex_color_t, ::boost::default_color_type> > Graph; typedef typename ::boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename ::boost::graph_traits<Graph>::edge_descriptor edge_descriptor; typedef const void* type_value; public: ::boost::mutex _mutex; Graph _graph; ::std::map<type_value, vertex_descriptor> _vertex; public: deadlock_graph() { } /**   * @return true     */ bool _cdecl insert(const void* locker_child, const void* locker_root) { using namespace ::boost; using namespace ::std; mutex::scoped_lock scoped_lock(_mutex); if(_vertex.end() == _vertex.find(locker_child)) { _vertex.insert(make_pair(locker_child, add_vertex(_graph) )); } if(_vertex.end() == _vertex.find(locker_root)) { _vertex.insert(make_pair(locker_root, add_vertex(_graph) )); } vertex_descriptor vertex_child = _vertex[locker_child]; pair<edge_descriptor, bool> ret = add_edge(vertex_child,_vertex[locker_root],_graph); if(ret.second) { bool has_cycle = false; cycle_detector vis(has_cycle); //_color_map.resize(num_vertices(_graph)); //= color_map(num_vertices(_graph)); //::std::fill(_color_map.begin(),_color_map.end(),white_color); graph_traits<Graph>::vertex_iterator vi, vi_end; for (tie(vi, vi_end) = vertices(_graph); vi != vi_end; ++vi) get(vertex_color, _graph)[*vi] = white_color; depth_first_visit(_graph, vertex_child, vis, get(vertex_color, _graph) ); if(has_cycle) { //  ,   . _graph.clear(); _vertex.clear(); } return !has_cycle; } return true; } }; inline char const* deadlock_shared_key() { return "1958EF20-6689-4e7b-9C53-3C115BCCF465"; } /** ,   : */ template<typename T> class main { deadlock_graph<T> _graph; public: main() { using namespace boost::interprocess; char process_id_str[20]; if(0 != _itoa_s(get_current_process_id(),process_id_str,sizeof(process_id_str),10)) { throw ::std::runtime_error(__FUNCTION__); } managed_shared_memory shmem(open_or_create, deadlock_shared_key(), 1024); shmem.construct<deadlock_graph<T>*>(process_id_str)(&_graph); } }; /** */ template<typename T> class checker { private: /**     .*/ struct main_ref { deadlock_graph_i<T>* & _graph_ptr; public: main_ref(deadlock_graph_i<T>* & graph_ptr) : _graph_ptr(graph_ptr) { } void operator()() const { using namespace boost::interprocess; char process_id_str[20]; if(0 != _itoa_s(get_current_process_id(),process_id_str,boost::size(process_id_str),10)) { throw ::std::runtime_error(__FUNCTION__); } managed_shared_memory shmem(open_read_only, deadlock_shared_key()); _graph_ptr = *shmem.find<deadlock_graph<T>*>(process_id_str).first; if(!_graph_ptr) { throw ::std::runtime_error(__FUNCTION__); } } }; private: /** ,    */ static boost::thread_specific_ptr<::std::stack<void*> > _stack; /** ,   : */ static deadlock_graph_i<T>* _graph_ptr; static boost::once_flag _graph_flag; public: /**     "locker"*/ static bool push(void* locker) { //     bool cycle_error = false; init_thread(); ::std::stack<void*>* lockers = _stack.get(); assert(lockers && lockers->size() < 8); if(lockers->size() > 0) { void* locker_root = lockers->top(); if(locker_root != locker) { //   -. char const * filename = ".\\Data\\deadlock.log"; if(!::boost::filesystem::is_regular_file(filename)) { //    . cycle_error = !_graph_ptr->insert(locker,locker_root); assert(!cycle_error && " deadlock"); if(cycle_error) { ::std::ofstream file(filename); if(file.is_open()) { file << "  deadlock" << ::std::endl; } } } } } lockers->push(locker); return cycle_error; }; /**     "locker"*/ static void pop(void* locker = 0) { ::std::stack<void*>* lockers = _stack.get(); assert(lockers && !lockers->empty()); assert(!locker || lockers->top() == locker); if(!lockers->empty()) { lockers->pop(); }; }; private: /**     */ static void init_thread() { if(!_stack.get()) { boost::call_once(_graph_flag, main_ref(_graph_ptr)); _stack.reset(new ::std::stack<T*>); } } }; template<typename T> boost::thread_specific_ptr<::std::stack<void*> > checker<T>::_stack; template<typename T> deadlock_graph_i<T>* checker<T>::_graph_ptr; template<typename T> boost::once_flag checker<T>::_graph_flag; /** */ template<> class checker<bool> { public: static bool push(void* /*locker*/, char* /*name*/) { return true; } /***/ static bool push(void* /*locker*/) { return true; }; /***/ static void pop(void* /*locker*/ = 0) { }; }; /** */ template<> class main<bool> { }; } #if defined(ENABLE_DEADLOCK_CHECKER) typedef deadlock_checker::checker<void> deadlock_checker_t; typedef deadlock_checker::main<void> deadlock_checker_main_t; #else typedef deadlock_checker::checker<bool> deadlock_checker_t; typedef deadlock_checker::main<bool> deadlock_checker_main_t; #endif 

Source: https://habr.com/ru/post/In201388/


All Articles