| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace ThreadManagerTest
- {
- public class ThreadManager
- {
- private readonly CameraGroup[] _cameraGroups = new CameraGroup[4];
- private CancellationTokenSource _communicationCts;
- private CancellationTokenSource _displayCts;
- private Task _communicationTask;
- private Task _displayTask;
- private bool _isCommunicationRunning = false;
- private bool _isDisplayRunning = false;
- // 用于存储待发送的结果数据的队列
- private readonly ConcurrentQueue<ProcessResultEventArgs> _resultQueue = new ConcurrentQueue<ProcessResultEventArgs>();
- private readonly SemaphoreSlim _resultSemaphore = new SemaphoreSlim(0);
- public ThreadManager()
- {
- // 初始化四个相机组
- for (int i = 0; i < 4; i++)
- {
- _cameraGroups[i] = new CameraGroup
- {
- CameraId = i,
- ImageQueue = new ConcurrentQueue<ImageData>(),
- QueueSemaphore = new SemaphoreSlim(0),
- CancellationTokenSource = new CancellationTokenSource()
- };
- // 订阅处理结果事件
- _cameraGroups[i].ProcessResultAvailable += OnProcessResultAvailable;
- }
- }
- /// <summary>
- /// 处理结果事件处理器
- /// 当任一相机组产生处理结果时都会调用此方法
- /// </summary>
- private void OnProcessResultAvailable(object sender, ProcessResultEventArgs e)
- {
- // 将结果数据加入队列
- _resultQueue.Enqueue(e);
- // 通知通信线程有新数据
- _resultSemaphore.Release();
- }
- /// <summary>
- /// 通信线程循环 - 修改版
- /// </summary>
- private async void CommunicationLoop(CancellationToken token)
- {
- try
- {
- while (!token.IsCancellationRequested)
- {
- // 等待结果数据
- await _resultSemaphore.WaitAsync(token);
- // 检查是否有待发送的结果
- if (_resultQueue.TryDequeue(out ProcessResultEventArgs result))
- {
- // 发送结果数据
- SendResultToCommunicationDevice(result);
- }
- // 1ms休眠
- await Task.Delay(1, token);
- }
- }
- catch (OperationCanceledException)
- {
- // 线程被取消,正常退出
- }
- catch (Exception ex)
- {
- Console.WriteLine($"通信线程异常: {ex.Message}");
- }
- }
- /// <summary>
- /// 发送结果数据到通信设备
- /// </summary>
- private void SendResultToCommunicationDevice(ProcessResultEventArgs result)
- {
- // 实际的通信发送逻辑
- Console.WriteLine($"发送相机{result.CameraId}的结果数据: " +
- $"目标数={((ProcessResultData)result.ResultData).TargetCount}, " +
- $"时间={result.Timestamp}");
- // 这里实现实际的串口、网络或其他通信协议发送逻辑
- }
- /// <summary>
- /// 启动指定相机组(包括采集和处理线程)
- /// </summary>
- /// <param name="cameraId">相机ID (0-3)</param>
- public void StartCameraGroup(int cameraId)
- {
- if (cameraId < 0 || cameraId >= 4)
- throw new ArgumentException("相机ID必须在0-3之间");
- var group = _cameraGroups[cameraId];
- if (group.IsRunning)
- return;
- // 重置取消令牌
- group.CancellationTokenSource = new CancellationTokenSource();
- var token = group.CancellationTokenSource.Token;
- // 启动相机采集线程
- group.CameraTask = Task.Factory.StartNew(() => CameraCaptureLoop(group, token),
- token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- // 启动图像处理线程
- group.ProcessingTask = Task.Factory.StartNew(() => ImageProcessingLoop(group, token),
- token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- group.IsRunning = true;
- Console.WriteLine($"相机组 {cameraId} 已启动");
- }
- /// <summary>
- /// 停止指定相机组
- /// </summary>
- /// <param name="cameraId">相机ID (0-3)</param>
- public async void StopCameraGroup(int cameraId)
- {
- if (cameraId < 0 || cameraId >= 4)
- throw new ArgumentException("相机ID必须在0-3之间");
- var group = _cameraGroups[cameraId];
- if (!group.IsRunning)
- return;
- // 发送取消信号
- group.CancellationTokenSource.Cancel();
- // 等待线程完成
- try
- {
- if (group.CameraTask != null)
- await group.CameraTask;
- if (group.ProcessingTask != null)
- await group.ProcessingTask;
- }
- catch (OperationCanceledException)
- {
- // 正常取消,忽略异常
- }
- group.IsRunning = false;
- Console.WriteLine($"相机组 {cameraId} 已停止");
- }
- /// <summary>
- /// 启动通信线程
- /// </summary>
- public void StartCommunicationThread()
- {
- if (_isCommunicationRunning)
- return;
- _communicationCts = new CancellationTokenSource();
- var token = _communicationCts.Token;
- _communicationTask = Task.Factory.StartNew(() => CommunicationLoop(token),
- token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- _isCommunicationRunning = true;
- Console.WriteLine("通信线程已启动");
- }
- /// <summary>
- /// 停止通信线程
- /// </summary>
- public async void StopCommunicationThread()
- {
- if (!_isCommunicationRunning)
- return;
- _communicationCts.Cancel();
- try
- {
- if (_communicationTask != null)
- await _communicationTask;
- }
- catch (OperationCanceledException)
- {
- // 正常取消,忽略异常
- }
- _isCommunicationRunning = false;
- Console.WriteLine("通信线程已停止");
- }
- /// <summary>
- /// 启动显示线程
- /// </summary>
- public void StartDisplayThread()
- {
- if (_isDisplayRunning)
- return;
- _displayCts = new CancellationTokenSource();
- var token = _displayCts.Token;
- _displayTask = Task.Factory.StartNew(() => DisplayLoop(token),
- token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- _isDisplayRunning = true;
- Console.WriteLine("显示线程已启动");
- }
- /// <summary>
- /// 停止显示线程
- /// </summary>
- public async void StopDisplayThread()
- {
- if (!_isDisplayRunning)
- return;
- _displayCts.Cancel();
- try
- {
- if (_displayTask != null)
- await _displayTask;
- }
- catch (OperationCanceledException)
- {
- // 正常取消,忽略异常
- }
- _isDisplayRunning = false;
- Console.WriteLine("显示线程已停止");
- }
- /// <summary>
- /// 启动所有线程组
- /// </summary>
- public void StartAll()
- {
- // 启动所有相机组
- for (int i = 0; i < 4; i++)
- {
- StartCameraGroup(i);
- }
- // 启动通信和显示线程
- StartCommunicationThread();
- StartDisplayThread();
- }
- /// <summary>
- /// 停止所有线程组
- /// </summary>
- public void StopAll()
- {
- // 停止所有相机组
- for (int i = 0; i < 4; i++)
- {
- StopCameraGroup(i);
- }
- // 停止通信和显示线程
- StopCommunicationThread();
- StopDisplayThread();
- }
- /// <summary>
- /// 检查指定相机组是否正在运行
- /// </summary>
- /// <param name="cameraId">相机ID</param>
- /// <returns>运行状态</returns>
- public bool IsCameraGroupRunning(int cameraId)
- {
- if (cameraId < 0 || cameraId >= 4)
- return false;
- return _cameraGroups[cameraId].IsRunning;
- }
- /// <summary>
- /// 检查通信线程是否正在运行
- /// </summary>
- public bool IsCommunicationRunning => _isCommunicationRunning;
- /// <summary>
- /// 检查显示线程是否正在运行
- /// </summary>
- public bool IsDisplayRunning => _isDisplayRunning;
- #region 线程执行逻辑
- /// <summary>
- /// 相机采集循环
- /// </summary>
- private void CameraCaptureLoop(CameraGroup group, CancellationToken token)
- {
- int frameCount = 0;
- try
- {
- while (!token.IsCancellationRequested)
- {
- // 模拟相机图像采集(无休眠,持续采集)
- var imageData = new ImageData
- {
- CameraId = group.CameraId,
- RawData = new byte[1024], // 模拟图像数据
- Timestamp = DateTime.Now,
- FrameNumber = frameCount++
- };
- // 将图像放入队列
- group.ImageQueue.Enqueue(imageData);
- group.QueueSemaphore.Release(); // 通知处理线程有新数据
- // 这里不添加休眠,保持最大帧率采集
- }
- }
- catch (OperationCanceledException)
- {
- // 线程被取消,正常退出
- }
- catch (Exception ex)
- {
- Console.WriteLine($"相机 {group.CameraId} 采集异常: {ex.Message}");
- }
- }
- /// <summary>
- /// 图像处理循环
- /// </summary>
- private async void ImageProcessingLoop(CameraGroup group, CancellationToken token)
- {
- try
- {
- while (!token.IsCancellationRequested)
- {
- // 等待图像数据
- await group.QueueSemaphore.WaitAsync(token);
- // 从队列获取图像
- if (group.ImageQueue.TryDequeue(out ImageData imageData))
- {
- // 执行图像处理逻辑
- ProcessImage(imageData,group);
- // 可以根据队列长度决定是否短暂休眠以避免过度占用CPU
- if (group.ImageQueue.Count == 0)
- {
- await Task.Delay(1, token); // 短暂让出CPU
- }
- }
- }
- }
- catch (OperationCanceledException)
- {
- // 线程被取消,正常退出
- }
- catch (Exception ex)
- {
- Console.WriteLine($"相机 {group.CameraId} 处理异常: {ex.Message}");
- }
- }
- /// <summary>
- /// 图像处理实现 - 修改版
- /// </summary>
- private void ProcessImage(ImageData imageData, CameraGroup group)
- {
- var stopwatch = System.Diagnostics.Stopwatch.StartNew();
- // 执行图像处理逻辑
- var result = PerformImageAnalysis(imageData);
- stopwatch.Stop();
- // 创建处理结果数据
- var resultData = new ProcessResultData
- {
- TargetCount = result.Targets.Count,
- TargetPositions = result.Targets.Select(t => t.Position).ToList(),
- ProcessingTimeMs = stopwatch.ElapsedMilliseconds,
- FrameNumber = imageData.FrameNumber,
- ConfidenceScore = result.AverageConfidence
- };
- // 发送处理结果
- group.SendProcessResult(resultData);
- Console.WriteLine($"相机 {imageData.CameraId} 处理帧 {imageData.FrameNumber},发现 {result.Targets.Count} 个目标");
- }
- /// <summary>
- /// 图像分析模拟方法
- /// </summary>
- private ImageAnalysisResult PerformImageAnalysis(ImageData imageData)
- {
- // 模拟图像分析过程
- Thread.Sleep(10); // 模拟处理时间
- // 模拟分析结果
- return new ImageAnalysisResult
- {
- Targets = new List<TargetInfo>
- {
- new TargetInfo
- {
- Position = new Point { X = 100, Y = 150 },
- Confidence = 0.95
- },
- new TargetInfo
- {
- Position = new Point { X = 200, Y = 300 },
- Confidence = 0.87
- }
- },
- AverageConfidence = 0.91
- };
- }
- /// <summary>
- /// 显示线程循环
- /// </summary>
- private async void DisplayLoop(CancellationToken token)
- {
- var stopwatch = System.Diagnostics.Stopwatch.StartNew();
- long targetFrameTime = 1000 / 24; // 24fps对应的时间间隔(ms)
- try
- {
- while (!token.IsCancellationRequested)
- {
- stopwatch.Restart();
- // 执行显示逻辑
- UpdateDisplay();
- stopwatch.Stop();
- long elapsed = stopwatch.ElapsedMilliseconds;
- // 动态调整休眠时间以维持24fps
- long sleepTime = Math.Max(0, targetFrameTime - elapsed);
- if (sleepTime > 0)
- {
- await Task.Delay((int)sleepTime, token);
- }
- }
- }
- catch (OperationCanceledException)
- {
- // 线程被取消,正常退出
- }
- catch (Exception ex)
- {
- Console.WriteLine($"显示线程异常: {ex.Message}");
- }
- }
- /// <summary>
- /// 显示更新实现
- /// </summary>
- private void UpdateDisplay()
- {
- // 实现显示更新逻辑
- Console.WriteLine("更新显示画面");
- }
- #endregion
- }
- /// <summary>
- /// 相机组配置和状态管理类
- /// 管理单个相机的采集和处理线程及相关资源
- /// </summary>
- public class CameraGroup
- {
- public int CameraId { get; set; }
- public bool IsRunning { get; set; }
- public CancellationTokenSource CancellationTokenSource { get; set; }
- public Task CameraTask { get; set; }
- public Task ProcessingTask { get; set; }
- public ConcurrentQueue<ImageData> ImageQueue { get; set; }
- public SemaphoreSlim QueueSemaphore { get; set; }
- // 结果发送事件,当图像处理完成时触发
- public event EventHandler<ProcessResultEventArgs> ProcessResultAvailable;
- /// <summary>
- /// 发送处理结果到通信线程的方法
- /// 多个线程可以共用此方法
- /// </summary>
- /// <param name="resultData">处理结果数据</param>
- public void SendProcessResult(object resultData)
- {
- var eventArgs = new ProcessResultEventArgs
- {
- CameraId = this.CameraId,
- ResultData = resultData,
- Timestamp = DateTime.Now
- };
- // 触发事件,通知订阅者有新的处理结果
- ProcessResultAvailable?.Invoke(this, eventArgs);
- }
- }
- /// <summary>
- /// 处理结果事件参数类
- /// 包含相机ID和处理结果数据
- /// </summary>
- public class ProcessResultEventArgs : EventArgs
- {
- /// <summary>
- /// 相机ID
- /// </summary>
- public int CameraId { get; set; }
- /// <summary>
- /// 处理结果数据
- /// </summary>
- public object ResultData { get; set; }
- /// <summary>
- /// 结果生成时间戳
- /// </summary>
- public DateTime Timestamp { get; set; }
- }
- /// <summary>
- /// 处理结果数据结构示例
- /// </summary>
- public class ProcessResultData
- {
- /// <summary>
- /// 检测到的目标数量
- /// </summary>
- public int TargetCount { get; set; }
- /// <summary>
- /// 目标位置坐标列表
- /// </summary>
- public List<Point> TargetPositions { get; set; }
- /// <summary>
- /// 处理耗时(毫秒)
- /// </summary>
- public long ProcessingTimeMs { get; set; }
- /// <summary>
- /// 图像帧编号
- /// </summary>
- public int FrameNumber { get; set; }
- /// <summary>
- /// 置信度评分
- /// </summary>
- public double ConfidenceScore { get; set; }
- }
- /// <summary>
- /// 点坐标结构
- /// </summary>
- public struct Point
- {
- public float X { get; set; }
- public float Y { get; set; }
- }
- /// <summary>
- /// 图像数据结构
- /// </summary>
- public class ImageData
- {
- public int CameraId { get; set; }
- public byte[] RawData { get; set; }
- public DateTime Timestamp { get; set; }
- public int FrameNumber { get; set; }
- }
- /// <summary>
- /// 图像分析结果类
- /// </summary>
- public class ImageAnalysisResult
- {
- public List<TargetInfo> Targets { get; set; }
- public double AverageConfidence { get; set; }
- }
- /// <summary>
- /// 目标信息类
- /// </summary>
- public class TargetInfo
- {
- public Point Position { get; set; }
- public double Confidence { get; set; }
- }
- }
|