/// <summary> /// Thread method /// </summary> private void Start() { var curTid = OSApi.GetCurrentThreadId(); var processThread = Process.GetCurrentProcess().Threads .OfType <ProcessThread>() .First(pt => pt.Id == curTid); processThread.IdealProcessor = _processorId; processThread.ProcessorAffinity = (IntPtr)(1 << _processorId); var token = _cancellationTokenSource.Token; var spinWait = new SpinWait(); var starvation = Stopwatch.StartNew(); while (!token.IsCancellationRequested) { if (TasksSource.TryDequeue(out var task)) { task.Action(task.State); starvation.Restart(); continue; } if (starvation.ElapsedMilliseconds > 300) { // If I have no work and exported to another context, // return me back to home context. Next iteration will loop // on home context's queue if (Exported) { _exportRegistration.Dispose(); _exportRegistration = null; continue; } // If I have no work, I can ask for work in another context // If another context in my host have any work, let's take // it's queue and join if (_host.TryNotifyIdle(this, out var registration)) { _exportRegistration = registration; } else { // else, go to blocking state _hasJobEvent.Reset(); _hasJobEvent.WaitOne(); starvation.Restart(); } } spinWait.SpinOnce(); } }
/// <summary> /// SyncContext thread function /// </summary> private void Start(object obj) { SetSynchronizationContext(this); var tinfo = (LocalThreadState)obj; var curTid = OSApi.GetCurrentThreadId(); var processThread = Process.GetCurrentProcess().Threads.OfType <ProcessThread>().First(pt => pt.Id == curTid); processThread.IdealProcessor = tinfo.ProcessorId; processThread.ProcessorAffinity = (IntPtr)(1 << tinfo.ProcessorId); tinfo.ProcessThread = processThread; var token = tinfo.CancellationTokenSource.Token; var spinWait = new SpinWait(); var starvation = Stopwatch.StartNew(); var invertingStarvation = Stopwatch.StartNew(); while (!token.IsCancellationRequested) { if (_tasks.TryDequeue(out var task)) { task.Action(task.State); starvation.Restart(); } else { if (starvation.ElapsedMilliseconds > 300) { Interlocked.Exchange(ref _hardLock, 1); _event.WaitOne(); starvation.Restart(); continue; } spinWait.SpinOnce(); } if (invertingStarvation.ElapsedMilliseconds > 5000) { invertingStarvation.Restart(); Invert(tinfo); } } }