Dreamine.Threading 1.0.1
이 패키지는 .NET ThreadPool이나 Task Parallel Library를 대체하려는 목적이 아닙니다.
로딩중...
검색중...
일치하는것 없음
DreamineThreadManager.cs
이 파일의 문서화 페이지로 가기
1using Dreamine.Logging.Interfaces;
4
6
16{
25 private readonly object _syncRoot = new();
34 private readonly List<IDreamineThread> _threads = new();
88 private readonly IDreamineLogger? _logger;
97 private bool _disposed;
98
164 IThreadCoreAllocator coreAllocator,
165 IThreadCyclePolicy cyclePolicy,
166 IDreamineThreadScheduler scheduler,
167 IThreadAffinityService? affinityService = null,
168 ITimerResolutionService? timerResolutionService = null,
169 IDreamineLogger? logger = null)
170 {
171 _coreAllocator = coreAllocator ?? throw new ArgumentNullException(nameof(coreAllocator));
172 _cyclePolicy = cyclePolicy ?? throw new ArgumentNullException(nameof(cyclePolicy));
173 _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
174 _affinityService = affinityService;
175 _timerResolutionService = timerResolutionService;
176 _logger = logger;
177 }
178
236 DreamineThreadOptions options,
237 Func<CancellationToken, ValueTask> action)
238 {
239 ArgumentNullException.ThrowIfNull(options);
240 ArgumentNullException.ThrowIfNull(action);
241
242 lock (_syncRoot)
243 {
245 }
246
247 var normalized = options.Normalize();
248 var assignment = _coreAllocator.Allocate(normalized);
249
250 try
251 {
252 var jobOptions = new DreamineThreadJobOptions
253 {
254 Name = normalized.Name,
255 IntervalMs = assignment.IsOverflowPolling
256 ? normalized.OverflowPollingIntervalMs
257 : normalized.IntervalMs,
258 IsEnabled = true,
259 IsOverflowPolling = assignment.IsOverflowPolling
260 };
261
262 var job = new DreamineThreadJob(jobOptions, action);
263
264 // Worker decisions are taken under the lock; thread Start() is
265 // performed afterwards to avoid running external callbacks
266 // (logging, affinity, etc.) while holding the manager lock.
267 IDreamineThread? workerToStart = null;
268
269 lock (_syncRoot)
270 {
272
273 if (assignment.IsOverflowPolling)
274 {
275 workerToStart = RegisterOverflowJob(job);
276 }
277 else
278 {
279 var worker = new DreamineThread(
280 normalized,
281 assignment,
285 _logger);
286
287 worker.AddJob(job);
288 _threads.Add(worker);
289
290 if (normalized.AutoStart)
291 {
292 workerToStart = worker;
293 }
294 }
295 }
296
297 workerToStart?.Start();
298
299 _logger?.Info(
300 $"Thread registered. Name={normalized.Name}, Core={assignment.CoreIndex}, Affinity={assignment.UseAffinity}");
301
302 return job;
303 }
304 catch
305 {
306 _coreAllocator.Release(assignment);
307 throw;
308 }
309 }
310
319 public void StartAll()
320 {
321 foreach (var thread in GetThreads())
322 {
323 thread.Start();
324 }
325 }
326
343 public void StopAll()
344 {
345 foreach (var thread in GetThreads())
346 {
347 thread.Stop();
348 }
349 }
350
367 public async ValueTask StopAllAsync()
368 {
369 foreach (var thread in GetThreads())
370 {
371 await thread.StopAsync().ConfigureAwait(false);
372 }
373 }
374
399 public bool Start(string threadName)
400 {
401 if (!TryGetThread(threadName, out var thread) || thread is null)
402 {
403 return false;
404 }
405
406 thread.Start();
407 return true;
408 }
409
442 public bool Stop(string threadName)
443 {
444 if (!TryGetThread(threadName, out var thread) || thread is null)
445 {
446 return false;
447 }
448
449 thread.Stop();
450 return true;
451 }
452
477 public async ValueTask<bool> StopAsync(string threadName)
478 {
479 if (!TryGetThread(threadName, out var thread) || thread is null)
480 {
481 return false;
482 }
483
484 await thread.StopAsync().ConfigureAwait(false);
485 return true;
486 }
487
512 public bool Pause(string threadName)
513 {
514 if (!TryGetThread(threadName, out var thread) || thread is null)
515 {
516 return false;
517 }
518
519 thread.Pause();
520 return true;
521 }
522
547 public bool Resume(string threadName)
548 {
549 if (!TryGetThread(threadName, out var thread) || thread is null)
550 {
551 return false;
552 }
553
554 thread.Resume();
555 return true;
556 }
557
566 public void PauseAll()
567 {
568 foreach (var thread in GetThreads())
569 {
570 thread.Pause();
571 }
572 }
573
582 public void ResumeAll()
583 {
584 foreach (var thread in GetThreads())
585 {
586 thread.Resume();
587 }
588 }
589
622 public bool TryGetThread(string threadName, out IDreamineThread? thread)
623 {
624 thread = null;
625
626 if (string.IsNullOrWhiteSpace(threadName))
627 {
628 return false;
629 }
630
631 lock (_syncRoot)
632 {
633 thread = _threads.FirstOrDefault(item =>
634 string.Equals(item.Name, threadName, StringComparison.Ordinal));
635
636 return thread is not null;
637 }
638 }
639
656 public IReadOnlyList<IDreamineThread> GetThreads()
657 {
658 lock (_syncRoot)
659 {
660 return _threads.ToArray();
661 }
662 }
663
680 public IReadOnlyList<DreamineThreadInfo> GetThreadInfos()
681 {
682 lock (_syncRoot)
683 {
684 return _threads
685 .Select(thread => thread.GetInfo())
686 .ToArray();
687 }
688 }
689
706 public void Dispose()
707 {
708 if (_disposed)
709 {
710 return;
711 }
712
713 StopAll();
714
715 lock (_syncRoot)
716 {
717 foreach (var thread in _threads)
718 {
719 thread.Dispose();
720 _coreAllocator.Release(thread.CoreAssignment);
721 }
722
723 _threads.Clear();
724 _disposed = true;
725 }
726 }
727
761 {
762 var worker = _scheduler.SelectWorker(_threads);
763 IDreamineThread? newWorker = null;
764
765 if (worker is null)
766 {
767 var fallbackOptions = new DreamineThreadOptions
768 {
769 Name = "DreamineOverflowWorker",
770 Priority = DreamineThreadPriority.Normal,
771 IntervalMs = 10,
772 CoreMode = DreamineThreadCoreMode.None,
773 AutoStart = true
774 };
775
776 var fallbackAssignment = DreamineThreadCoreAssignment.None();
777
778 newWorker = new DreamineThread(
779 fallbackOptions,
780 fallbackAssignment,
784 _logger);
785
786 _threads.Add(newWorker);
787 worker = newWorker;
788 }
789
790 worker.AddJob(job);
791
792 _logger?.Warning(
793 $"Overflow polling job registered. Job={job.Name}, Worker={worker.Name}");
794
795 return newWorker;
796 }
797
814 private void ThrowIfDisposed()
815 {
816 if (_disposed)
817 {
818 throw new ObjectDisposedException(nameof(DreamineThreadManager));
819 }
820 }
821}
void AddJob(IDreamineThreadJob job)
DreamineThreadManager(IThreadCoreAllocator coreAllocator, IThreadCyclePolicy cyclePolicy, IDreamineThreadScheduler scheduler, IThreadAffinityService? affinityService=null, ITimerResolutionService? timerResolutionService=null, IDreamineLogger? logger=null)
bool TryGetThread(string threadName, out IDreamineThread? thread)
IDreamineThreadJob Register(DreamineThreadOptions options, Func< CancellationToken, ValueTask > action)
readonly? ITimerResolutionService _timerResolutionService
async ValueTask< bool > StopAsync(string threadName)
IReadOnlyList< DreamineThreadInfo > GetThreadInfos()
IDreamineThread? RegisterOverflowJob(IDreamineThreadJob job)