Low bridging between threads in one process

The console application has 3 threads: Main, T1, T2. The goal is to “signal” as T1, T2 (and let them do some work) from the main thread in the least delay as possible (μs)

NOTE.

  • Please ignore Jitter, GC, etc. (I can handle this)
  • Call Cost ElapsedLogger.WriteLine below 50 ns (nano sec)

Take a look at the code below:

sample 1

class Program { private static string msg = string.Empty; private static readonly CountdownEvent Countdown = new CountdownEvent(1); static void Main(string[] args) { while (true) { Countdown.Reset(1); var t1 = new Thread(Dowork) { Priority = ThreadPriority.Highest }; var t2 = new Thread(Dowork) { Priority = ThreadPriority.Highest }; t1.Start(); t2.Start(); Console.WriteLine("Type message and press [enter] to start"); msg = Console.ReadLine(); ElapsedLogger.WriteLine("Kick off!"); Countdown.Signal(); Thread.Sleep(250); ElapsedLogger.FlushToConsole(); } } private static void Dowork() { string t = Thread.CurrentThread.ManagedThreadId.ToString(); ElapsedLogger.WriteLine("{0} - Waiting...", t); Countdown.Wait(); ElapsedLogger.WriteLine("{0} - Message received: {1}", t, msg); } } 

Output:

 Type message and press [enter] to start test3 20141028 12:03:24.230647|5 - Waiting... 20141028 12:03:24.230851|6 - Waiting... 20141028 12:03:30.640351|Kick off! 20141028 12:03:30.640392|5 - Message received: test3 20141028 12:03:30.640394|6 - Message received: test3 Type message and press [enter] to start test4 20141028 12:03:30.891853|7 - Waiting... 20141028 12:03:30.892072|8 - Waiting... 20141028 12:03:42.024499|Kick off! 20141028 12:03:42.024538|7 - Message received: test4 20141028 12:03:42.024551|8 - Message received: test4 

In the above "latency" code is about 40-50 μs. The CountdownEvent callback is very cheap (less than 50 ns), but the T1, T2 streams are paused and it takes time to wake them up.

sample 2

 class Program { private static string _msg = string.Empty; private static bool _signal = false; static void Main(string[] args) { while (true) { _signal = false; var t1 = new Thread(Dowork) {Priority = ThreadPriority.Highest}; var t2 = new Thread(Dowork) {Priority = ThreadPriority.Highest}; t1.Start(); t2.Start(); Console.WriteLine("Type message and press [enter] to start"); _msg = Console.ReadLine(); ElapsedLogger.WriteLine("Kick off!"); _signal = true; Thread.Sleep(250); ElapsedLogger.FlushToConsole(); } } private static void Dowork() { string t = Thread.CurrentThread.ManagedThreadId.ToString(); ElapsedLogger.WriteLine("{0} - Waiting...", t); while (!_signal) { Thread.SpinWait(10); } ElapsedLogger.WriteLine("{0} - Message received: {1}", t, _msg); } } 

Output:

 Type message and press [enter] to start testMsg 20141028 11:56:57.829870|5 - Waiting... 20141028 11:56:57.830121|6 - Waiting... 20141028 11:57:05.456075|Kick off! 20141028 11:57:05.456081|6 - Message received: testMsg 20141028 11:57:05.456081|5 - Message received: testMsg Type message and press [enter] to start testMsg2 20141028 11:57:05.707528|7 - Waiting... 20141028 11:57:05.707754|8 - Waiting... 20141028 11:57:57.535549|Kick off! 20141028 11:57:57.535576|7 - Message received: testMsg2 20141028 11:57:57.535576|8 - Message received: testMsg2 

This time, "latency" is about 6-7 μs. (but high CPU) This is due to the fact that threads T1, T2 are forcibly activated (they do nothing, just record the processor time)

In a "real" application, I can’t rotate the processor like that (I have many active threads, and this will make it worse / slower or even kill the server).

Can I use something that I can use to drop latency by about 10-15 microseconds? I think that with the Producer / Consumer template it will not work faster than with the CountdownEvent. Wait / Pulse is also more expensive than CountdownEvent.

What I got in example 1, how much can I achieve?

Any suggestions?

I will also try raw sockets when I have time.

+6
source share
2 answers

I agree that the SpinWait () approach is unrealistic for use in production. Your streams will have to fall asleep and wake up.

I see that you are looking at waiting / Pulse. Have you compared any other primitives available in .net? Joe Albahari "Threading in C #" has an exhaustive overview of all your options. http://www.albahari.com/threading/part4.aspx#_Signaling_with_Wait_and_Pulse

One point I want to touch on: how confident are you about the timestamps created by ElapsedLogger?

+1
source

Not much that can be done, since another thread needs to be scheduled by the OS.

Increasing the priority of the waiting thread is the only thing that can make a big difference, and you already did it. You could go even higher.

If you really need the lowest possible latency to activate another task, you must turn it into a function that can be called directly from the initiating thread.

+1
source

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


All Articles