C # resolves deadlocks

Source: Internet
Author: User
Tags static class

Dealing with this deadlock problem, spent several days, I believe that the classmate met, same headache, but there is a good helper class words (fortunately. NET API is strong enough), there is no such a headache attention

The solution for this article is only for use with lock (obj) or: Monitor.Enter (obj); .... The way Monitor.Exit (obj)
A deadlock similar to purple

If you are using: Autoresetevent.set/rest, Monitor.wait/pulse, Mutex way, please find another method. Auxiliary class

------------------------------------------------------------------------//craeted by Jave.lin 4/21/2018 5:31:57
PM//------------------------------------------------------------------------using System;
Using System.Collections.Generic;

Using System.Threading; namespace Common.comutil//{///<summary>///Locker information///author:Jave.Lin///dat 

        e:4/21/2018 5:31:57 PM///</summary> public class Locker {public object tag;//Incidental context data public int ThreadID; Gets the thread ID public string name of the lock; The name of the lock is public int lockedtimes; How many times the cumulative acquisition lock is convenient for analyzing the deadlock probability public int lockingts; Gets the timestamp of the lock that moment public bool enter; Gets the token of the lock public bool exit; The token that releases the lock is public string lockingstacktrace; Gets the call method stack at the moment of the lock, the following dumps information instance can be seen very clearly public int lockingdlts;

        The timestamp public list<locker> precordlist is set when it is identified as a deadlock; Public Locker (string name) {THIS.name= name;
        Precordlist = new list<locker> ();
        public void Pushrecord () {Precordlist.add (Retrieverecord ());
        public void Clearrecord () {precordlist.clear ();
            Public Locker Retrieverecord () {var ret = new Locker (this.name);
            Ret.tag = tag;
            Ret.threadid = ThreadID;
            Ret.name = name;
            Ret.lockedtimes = Lockedtimes;
            Ret.lockingts = Lockingts;
            Ret.enter = Enter;
            Ret.exit = exit;
            Ret.lockingstacktrace = Lockingstacktrace;
            Ret.lockingdlts = Lockingdlts;
        return ret;
                public override string ToString () {string[] STRs = new string[] { "ThreadId:" + ThreadId, "name:" + Name, "Lockedtimes:" + lockedtimes, "
              Lockingts: "+ Lockingts,  "Locinget:" + (Lockingdlts-lockingts) + ("(ms"), "Enter:" + Enter, "exit:" + exit, "Tag:" + (tag!= null?) Tag. ToString (): "null"), "lockingstacktrace:\n" + Lockingstacktrace, (Precordlist.count > 0? "Lockedrecord:\n\t" + string.
            Join ("\t-record--------------", precordlist): "")}; return string.
        Join ("\ r \ n", STRs);
    } public delegate void Ondl ();
    <summary>///Check Dead Lock (CDL)///author:Jave.Lin///date:4/21/2018 5:31:57 PM </summary> public static class CDL {//had been locked into map public static readonly
        Dictionary<locker, bool> _s_plockedmap = new Dictionary<locker, bool> (); The last public static readonly Dictionary<locker, list<locker>> _s_plockingmap = new DICTIONARY&L T

        Locker, list<locker>> (); Public Constbool Throw_er = true; public const int dead_lock_time_out = 3000;

        This valve value on demand adjustment, the actual online product Server program if the load is too large, may also have some tasks to deal with too long, leading to ' take lock ' waiting for too long public static event Ondl Ondlevent;
            private static void _pushtowaitqueue (Locker Locker) {list<locker> List = null;
                if (!_s_plockingmap.trygetvalue (locker, out list) {list = new list<locker> ();
            _s_plockingmap[locker] = list; } list. Add (Locker.
        Retrieverecord ());
            private static void _clearfromlocking (Locker Locker) {list<locker> List = null; if (_s_plockingmap.trygetvalue (locker, out list)) {list.
                Clear ();
            _s_plockingmap.remove (Locker); 
                }} private static void _beforeenter (Locker Locker) {if (locker.enter) { Locker.
                Pushrecord (); _pushtowaitqUeue (Locker);
            } private static void _enter (Locker Locker) {locker.enter = true;
            Locker.exit = false;
            Locker.lockingts = Environment.tickcount;
            Locker.threadid = Thread.CurrentThread.ManagedThreadId;
            Locker.lockingstacktrace = Getcurstacktrace ("->\n");

            Interlocked.Increment (ref locker.lockedtimes);
        _s_plockedmap[locker] = true; private static void _exit (Locker Locker) {if (!
                Monitor.isentered (Locker)) {Locker.lockingts = Environment.tickcount; var msg = "!
                Monitor.isentered (Locker) ";
                if (throw_er) {THROW new Exception (msg);
                else {_warningwriteline (msg);
         } else {locker.exit = true;       _s_plockedmap.remove (Locker);
                _clearfromlocking (Locker); Locker.
                Clearrecord ();
            Monitor.Exit (Locker); }} private static string _getwaitqueue (Locker Locker) {if (_s_plockingmap.containske Y (Locker)) {return string.
            Join ("\n@@@@@", _s_plockingmap[locker]);
        Return "";
            public static string dumps () {var itemList = new list<locker> ();
            var contentlist = new list<string> (); foreach (var item in _s_plockedmap) {Itemlist.add (item.
            Key); } itemlist.sort ((A, B) => {return (B.lockingdlts-b.lockingts)-(A.LOCKINGDL
            TS-A.LOCKINGTS);
            }); foreach (var item in itemList) {Contentlist.add (item. ToString () + "\n$$$$$$$$$ $Before locking WAITQueue$$$$$$$$\n "+ _getwaitqueue (item)); return string.
        Join ("\r\n=line============\r\n", ContentList);
                public static void Checkdl (Locker Locker, Action actoin) {try {
                _beforeenter (Locker);

                    if (Monitor.TryEnter (Locker, Dead_lock_time_out)) {_enter (locker); Actoin.
                Invoke ();
                    else {locker.lockingdlts = Environment.tickcount;
                    _warningwriteline ("TryEnter Time Out");
                    if (throw_er) {_showgetlocktimeout (); else {Actoin.
                    Invoke (); The catch (Exception e) {_errorwriteline (e.tostring
            ());
     }       Finally {_exit (locker); }} public static T checkdl<t> (Locker Locker, func<t> actoin) {t ret = de
            Fault (T);
                try {_beforeenter (locker);

                    if (Monitor.TryEnter (Locker, Dead_lock_time_out)) {_enter (locker); ret = Actoin.
                Invoke ();
                    else {locker.lockingdlts = Environment.tickcount;
                    _warningwriteline ("TryEnter Time Out");
                    if (throw_er) {_showgetlocktimeout (); else {Actoin.
                    Invoke (); The catch (Exception e) {_errorwriteline (e.tostring
            ());
         }   Finally {_exit (locker);
        return ret; public static string Getcurstacktrace (String separactor = "->") {System.Diagnostics.Stac
            Ktrace st = new System.Diagnostics.StackTrace (); system.diagnostics.stackframe[] SFS = St.
            Getframes ();
            list<string> methodnamelist = new list<string> (); for (int i = 1; i < SFS. Length; ++i) {if (System.Diagnostics.StackFrame.OFFSET_UNKNOWN = = Sfs[i].
                Getiloffset ()) break; var m = sfs[i].
                GetMethod ();
                var DN = m.declaringtype.name;
                var mn = M.name; Methodnamelist.add (New String (', SFS.
            Length-i + DN + "::" + mn + "()");

            } methodnamelist.reverse (); return string.
        Join (Separactor, methodnamelist); private static void _showgetlocktimeout () {ondlevent?. INvoke (); var msg = "!!!!!!!!!!!!!!!!!!
            Deadlock!!!!!!!!!!!!!!!!!!!!!!!!!! ";
            _errorwriteline (msg);
        throw new Exception (msg); } private static void _errorwriteline (String msg, params object[] args) {var srccolor = Conso Le.
            Foregroundcolor;
            Console.foregroundcolor = consolecolor.red;
            Console.WriteLine (msg, args);
        Console.foregroundcolor = Srccolor; } private static void _warningwriteline (String msg, params object[] args) {var srccolor = Con Sole.
            Foregroundcolor;
            Console.foregroundcolor = Consolecolor.yellow;
            Console.WriteLine (msg, args);
        Console.foregroundcolor = Srccolor;

 }
    }
//}
main points of use, attention to side effects, treatment side effects main points of use method
Our usual:
lock (obj)
{
 //code here} is

rewritten as:
CDL. CHECKDL (obj, () =>
{
 //code here
});

How convenient to change, is a problem
//Use lock less words, manually change it
//If the vast number of words, we recommend CTRL + SHIFT + H to bulk replace the lock code (write a regular)
/ Will: The namespace of the CDL is removed, so that you do not have to guide namespace.

Once a deadlock occurs, it will hit the Cdl::_showgetlocktimeout method
Then print out the contents of the Cdl.dumps () to see which cdl.checkdl are currently deadlocked.
Dumps is very detailed, specific can also according to their own needs to locker information to make adjustments. identifying deadlocks from dumps information

Dumps information, identify which is the deadlock state, see: Lockinget value is how much you know
Lockinget is: The meaning of locking Elapsed time, how long has the lock been acquired
Lockinget value is greater than 0 and is close to: cdl.dead_lock_time_out value, essentially deadlock pay attention to side effects

Obviously, the original code logic will change.
There are a few more ways to call
In particular, the location of the original code, changed, and placed a lambda (in fact, an anonymous function in IL)
Not to mention the structural changes, efficiency will also have the impact of loss. Handling Side Effects

There is also a way to go out side effects, is to write a tool, will compile the DLL, batch processing CDL.CHECKDL IL code, changed to the original lock (obj) way, of course, the premise is to need a lot of testing before using this tool to deal with, or if there is a deadlock in the middle of the word, Positioning problems can still be a headache. (Making this tool is theoretically possible, but needs to be familiar with IL) Note cdl.dead_lock_time_out

CDL. dead_lock_time_out= 3000; This valve value on demand adjustment, the actual online product Server program if the load is too large, may also have some tasks to deal with too long, leading to the ' lock ' waiting for too long, so appear monitor. When TryEnter timeout, it is not necessarily a deadlock.
You can adjust the value according to your needs, such as: Adjust A: 60000 (60 seconds), meaning that you have determined that the lock time timeout of 60 seconds, is a deadlock task to cause the CDL. Dumps content Instance

Threadid:10 name:cbcserveralivelocker lockedtimes:1 lockingts:7496815 lockinget:-7496815 (MS//========= identification of deadlocks ======= Negative numbers don't look enter:true exit:false tag:null lockingstacktrace:program::main ()-> xxxserver::waitforexit () -> cdl::checkdl () =line============ threadid:15 name:ctcpnetworker lockedtimes:486 LockingTs:7519248 Locking et:2995 (MS//= Identify deadlock = This is a deadlock also, close to the value of Cdl.dead_lock_time_out (3000 ms), locker Exit due to a lock timeout of cbattleroom enter:true thread ID 6:
  False tag:null lockingstacktrace: _iocompletioncallback::P erformiocompletioncallback ()->
    Baseoverlappedasyncresult::completionportcallback ()-> lazyasyncresult::P rotectedinvokecallback ()-> Contextawareresult::complete ()-> executioncontext::run ()-> executioncontext::run ()-> ExecutionC
          Ontext::runinternal ()-> contextawareresult::completecallback ()-> lazyasyncresult::complete ()-> Xxxnetworker::_onbeginreceivecallback ()-> CDL::CHECKDL() =line============ threadid:15 name:ceventmgr lockedtimes:247 lockingts:7519248 lockinget:-7519248 (MS//========= Identify deadlocks ======= Negative numbers don't look enter:true exit:false tag:null lockingstacktrace:: Performiocompletioncallback ()-> baseoverlappedasyncresult::completionportcallback ()-> LazyAsyncResult:: Protectedinvokecallback ()-> contextawareresult::complete ()-> executioncontext::run ()-> ExecutionCo
         Ntext::run ()-> executioncontext::runinternal ()-> contextawareresult::completecallback ()->
            Lazyasyncresult::complete ()-> xxxnetworker::_onbeginreceivecallback ()-> cdl::checkdl ()-> <>c__displayclass78_0::<_onbeginreceivecallback>b__0 ()-> Xxxconnection::xxxnetworker _onpackageevent ()-> ceventmgr::invoke ()-> cdl::checkdl () =line============ threadid:6 N Ame:cbattleroommgr lockedtimes:689 lockingts:7519248 lockinget:-7519248 (MS//========= identify deadlocks ======= negative numbers do not need to see Enter:true exit:false tag:null: lockingstacktrace:: Performwaitcallback ()-> threadpoolworkqueue::D ispatch ()-> Task:: System.Threading.IThreadPoolWorkItem.ExecuteWorkItem ()-> task::executeentry ()-> Task::executewiththreadloc Al ()-> executioncontext::run ()-> executioncontext::runinternal ()-> task::executioncontextcal Lback ()-> task::execute ()-> task::innerinvoke ()-> xxxserver::<startup>b__36_0 ()-> cdl::checkdl ()-> xxxserver::<startup>b__36_1 ()-> Xxxserver::_de 
Adlockmethod ()-> xxxserverinst::_deadlockmethod1 ()-> cdl::checkdl () =line============ Threadid:6 name:cbattleroom lockedtimes:802 lockingts:7519248 lockinget:2995 (MS//============== Identify deadlock = = This is the deadlock also, Close to Cdl.dead_lock_time_out (3000 MS) value enter:true exit:false tag:broadcastall3 LoCkingstacktrace: _threadpoolwaitcallback::P erformwaitcallback ()-> threadpoolworkqueue::D ispatch ()-> Task:: System.Threading.IThreadPoolWorkItem.ExecuteWorkItem ()-> task::executeentry ()-> Task::executewiththreadloc Al

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.