当前位置:网站首页>Write it down once Net analysis of thread burst height of an industrial control data acquisition platform

Write it down once Net analysis of thread burst height of an industrial control data acquisition platform

2022-07-04 19:46:00 Yixiandiannong

One : background

1. Tell a story

A few days ago, a friend was B standing Add it to me , Said his program appeared Number of threads The problem of explosion height , Let me help you see what happened , The screenshot is as follows :

Strange to say , These days, I have encountered several unexplained explosion in the number of threads , But those questions are much more complicated than this one , It mainly involves the unmanaged level , The main purpose of sharing this article is that it is very representative , It is necessary to .

Without further ado , Since the number of threads has exploded , Then go ahead windbg speak .

Two :WinDbg analysis

1. Is the number of threads really high

Since the number of threads is high , How many are there ? We can use !t Order to have a look .


0:000> !t
ThreadCount:      109
UnstartedThread:  0
BackgroundThread: 104
PendingThread:    0
DeadThread:       1
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
   0    1 2970 00581020     26020 Preemptive  0294AE60:00000000 0057a5f0 0     STA 
   2    2 1d2c 00590670     2b220 Preemptive  00000000:00000000 0057a5f0 0     MTA (Finalizer) 
   5    4 3388 0063a9b8   102a220 Preemptive  00000000:00000000 0057a5f0 0     MTA (Threadpool Worker) 
   6    5 265c 0063b458   1020220 Preemptive  00000000:00000000 0057a5f0 0     Ukn (Threadpool Worker) 
   7    7 3370 07100fa8   202b220 Preemptive  00000000:00000000 0057a5f0 0     MTA 
 ...
 113   41 4af4 0a85a490   8029220 Preemptive  0294F918:00000000 0057a5f0 0     MTA (Threadpool Completion Port) 
 114   75 4b9c 0a83d818   8029220 Preemptive  00000000:00000000 0057a5f0 0     MTA (Threadpool Completion Port) 
 115   76 4ba0 0a83d2d0   8029220 Preemptive  02B53AC4:00000000 0057a5f0 0     MTA (Threadpool Completion Port) 

From the perspective of hexagrams , The current is 115 Managed threads , From the main thread STA Mode view It should be a WinForm/WPF Program , The number of threads in desktop programs is not much , There's a lot less to say , The next step is to see what these threads are doing .

2. What are these threads doing

Explore what each thread is doing , It can be used ~*e !clrstack Call up all thread stacks , Then carefully and patiently observe these threads .


0:000> ~*e !clrstack 
OS Thread Id: 0x488c (109)
Child SP       IP Call Site
114de760 7704018d [GCFrame: 114de760] 
114de90c 7704018d [GCFrame: 114de90c] 
114de8bc 7704018d [HelperMethodFrame: 114de8bc] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
114de94c 6dfe2767 System.Threading.Monitor.Enter(System.Object, Boolean ByRef)
114de95c 056107e3 CSRedis.Internal.IO.RedisIO.Write(Byte[])
114de998 05cb338c CSRedis.Internal.RedisConnector.Write(CSRedis.RedisCommand)
114de9dc 05cb32fc CSRedis.Internal.RedisListener`1[[System.__Canon, mscorlib]].Write[[System.__Canon, mscorlib]](CSRedis.RedisCommand`1<System.__Canon>)
114de9f0 05cb3263 CSRedis.Internal.SubscriptionListener.Send(CSRedis.Internal.Commands.RedisSubscription)
114dea0c 050c4ffd CSRedis.RedisClient.Unsubscribe(System.String[])
114dea24 050c01e3 CSRedis.CSRedisClient+SubscribeObject+c__DisplayClass13_0.b__1(System.Object)
114deab4 6e026471 System.Threading.TimerQueueTimer.CallCallbackInContext(System.Object)
114deab8 6dfe2925 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
114deb24 6dfe2836 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
114deb38 6e026377 System.Threading.TimerQueueTimer.CallCallback()
114deb6c 6e0261fe System.Threading.TimerQueueTimer.Fire()
114debac 6e02612f System.Threading.TimerQueue.FireNextTimers()
114debec 6e025ff1 System.Threading.TimerQueue.AppDomainTimerCallback()
114dee10 6f38eaf6 [DebuggerU2MCatchHandlerFrame: 114dee10] 
...

From the perspective of hexagrams , Thread characteristics are very obvious , Yes 86 A thread is stuck in Monitor.ReliableEnter It's about , It's us C# Medium Watch the lock , Since it's a surveillance lock , That's easy , View its Synchronous block table , Look who is lock Other threads wait because they can't wait inside , Use windbg Of !syncblk command .


0:000> !syncblk
Index         SyncBlock MonitorHeld Recursion Owning Thread Info          SyncBlock Owner
   72 005ef1f0           87         1 07176838 12c8  13   028374e4 System.Object
   75 005efd1c           87         1 07176d80 32c0  14   028368ec System.Object
-----------------------------
Total           84
CCW             0
RCW             1
ComClassFactory 0
Free            17

From the table , There are currently two lock object , And threads 13 and 14 stay lock Don't come out of the area , Lead to their own 43 Threads are waiting , Next, the idea is very clear , Let's see what these two threads are doing ?

3. Hold what the thread is doing

We are from 13 Start with thread , Look what it is doing .


0:013> !clrstack 
OS Thread Id: 0x12c8 (13)
Child SP       IP Call Site
0971eb84 7703f901 [InlinedCallFrame: 0971eb84] 
0971eb80 6c5b940f DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
0971eb84 6c55b11d [InlinedCallFrame: 0971eb84] System.Net.UnsafeNclNativeMethods+OSSOCK.recv(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
0971ebbc 6c55b11d System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
0971ebec 6c55b00e System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags)
0971ec10 6c55af43 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
0971ec40 6e05add8 System.IO.Stream.ReadByte()
0971ec50 05610d2c CSRedis.Internal.IO.RedisIO.ReadByte()
0971ec8c 05610c5a CSRedis.Internal.IO.RedisReader.ReadType()
0971ecb0 05610a9e CSRedis.Internal.IO.RedisReader.ExpectType(CSRedis.RedisMessage)
0971ed28 05cb3696 CSRedis.Internal.Commands.RedisSubscription.Parse(CSRedis.Internal.IO.RedisReader)
0971ed90 05cb35bd CSRedis.Internal.RedisConnector.Read[[System.__Canon, mscorlib]](System.Func`2<CSRedis.Internal.IO.RedisReader,System.__Canon>)
0971ede0 05cb3487 CSRedis.Internal.RedisListener`1[[System.__Canon, mscorlib]].Listen(System.Func`2<CSRedis.Internal.IO.RedisReader,System.__Canon>)
0971ee34 05cb32b9 CSRedis.Internal.SubscriptionListener.Send(CSRedis.Internal.Commands.RedisSubscription)
0971ee50 05cb3156 CSRedis.RedisClient.Subscribe(System.String[])
0971ee68 05cb255a CSRedis.CSRedisClient+SubscribeObject.Subscribe(System.Object)
0971ef98 6dfb6063 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
0971efa4 6dfe2925 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
0971f010 6dfe2836 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
0971f024 6dfe27f1 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
0971f03c 6e036ebe System.Threading.ThreadHelper.ThreadStart(System.Object)
0971f180 6f38eaf6 [GCFrame: 0971f180] 
0971f364 6f38eaf6 [DebuggerU2MCatchHandlerFrame: 0971f364] 

From the thread stack , This friend used CSRedis The subscription function of , Last in CSRedis.Internal.IO.RedisIO.ReadByte() The method is too late , The problem has been found , Next, you can take a look at its source code .

4. View source code

Look at the source code , It can be used ILSpy Tools , The compiled code is as follows :

Actually, this place is used lock The lock is not secure , Once there are network fluctuations , Hold the thread and wait , If this thread is made by ThreadPool Provide , That would lead to ThreadPool The number of threads in has exploded , from Waiting Trace on the thread , It is found that the number of threads is determined by Timer Provide , The thread stack and screenshot are as follows :


OS Thread Id: 0x40e8 (67)
Child SP       IP Call Site
0e7af608 7704018d [GCFrame: 0e7af608] 
0e7af7b4 7704018d [GCFrame: 0e7af7b4] 
0e7af764 7704018d [HelperMethodFrame: 0e7af764] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
0e7af7f4 6dfe2767 System.Threading.Monitor.Enter(System.Object, Boolean ByRef)
0e7af804 056107e3 CSRedis.Internal.IO.RedisIO.Write(Byte[])
0e7af840 05cb338c CSRedis.Internal.RedisConnector.Write(CSRedis.RedisCommand)
0e7af884 05cb32fc CSRedis.Internal.RedisListener`1[[System.__Canon, mscorlib]].Write[[System.__Canon, mscorlib]](CSRedis.RedisCommand`1<System.__Canon>)
0e7af898 05cb3263 CSRedis.Internal.SubscriptionListener.Send(CSRedis.Internal.Commands.RedisSubscription)
0e7af8b4 050c4ffd CSRedis.RedisClient.Unsubscribe(System.String[])
0e7af8cc 050c01e3 CSRedis.CSRedisClient+SubscribeObject+c__DisplayClass13_0.b__1(System.Object)
0e7af95c 6e026471 System.Threading.TimerQueueTimer.CallCallbackInContext(System.Object)

3、 ... and : summary

Overall analysis , This is supposed to be CSRedis One of the Bug, What I can do about this problem is to let my friends upgrade to the latest version , But since it is Bug Then others will definitely meet , Looked at the CSRedis.dll Assembly to github Address .


[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("CSRedisCore")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("CSRedis  yes  redis.io  Official recommendation Library , Support  redis-trib colony 、 sentry 、 Private partition and connection pool management technology , Simple and easy  RedisHelper  Static class .")]
[assembly: AssemblyFileVersion("3.6.6.0")]
[assembly: AssemblyInformationalVersion("3.6.6")]
[assembly: AssemblyProduct("CSRedisCore")]
[assembly: AssemblyTitle("CSRedisCore")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/2881099/csredis")]
[assembly: AssemblyVersion("3.6.6.0")]

As expected Issueshttps://github.com/2881099/csredis/issues/414 ) Found the same problem in , It's a pity that the author didn't give an answer .

Say an interesting thing , I looked at the nickname of the questioner thicktao Seems familiar with , There seems to be this friend on wechat .

I went to , He came to me last year ,.NET The circle is really small , Fate ha ...

 Image name
原网站

版权声明
本文为[Yixiandiannong]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207041806445750.html