- public class CoreThreadPool : IDisposable
- {
- /// <summary>
- /// 队列元素申明
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- private class PoolData
- {
- /// <summary>
- /// 外部要求放入队列的数据
- /// </summary>
- public object Data;
- /// <summary>
- /// 需要执行的命令(Exit/Command(自定义))
- /// </summary>
- public PoolCommand Command;
- public PoolData()
- {
- Command = PoolCommand.Exit;
- }
- public PoolData(object data)
- {
- Data = data;
- Command = PoolCommand.Command;
- }
- public PoolData(PoolCommand cmd)
- {
- Command = cmd;
- }
- }
- protected enum PoolCommand
- {
- Command,
- Exit
- }
- protected SafeFileHandle complatePort;
- /// <summary>
- /// 线程池主线程
- /// </summary>
- protected Thread thread;
- protected volatile bool isOpened;
- [method: CompilerGenerated]
- [CompilerGenerated]
- public event Action<object> Exceute;
- [method: CompilerGenerated]
- [CompilerGenerated]
- public event Action<object> ExitExceute;
- /// <summary>
- /// 线程池是否正在运行
- /// </summary>
- public bool IsOpened
- {
- get
- {
- return this.isOpened;
- }
- set
- {
- this.isOpened = value;
- }
- }
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern SafeFileHandle CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, IntPtr CompletionKey, uint NumberOfConcurrentThreads);
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern bool GetQueuedCompletionStatus(SafeFileHandle CompletionPort, out uint lpNumberOfBytesTransferred, out IntPtr lpCompletionKey, out IntPtr lpOverlapped, uint dwMilliseconds);
- [DllImport("Kernel32", CharSet = CharSet.Auto)]
- private static extern bool PostQueuedCompletionStatus(SafeFileHandle CompletionPort, uint dwNumberOfBytesTransferred, IntPtr dwCompletionKey, IntPtr lpOverlapped);
- /// <summary>
- /// 启动线程池的主线程
- /// </summary>
- public void Start()
- {
- isOpened = true;
- if (thread != null)
- {
- throw new Exception("线程池已经是启动状态!");
- }
- complatePort = CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, IntPtr.Zero, 0u);
- if (complatePort.IsInvalid)
- {
- throw new Exception(string.Format("创建IOCP出错!原因是:{0}", Marshal.GetLastWin32Error().ToString()));
- }
- thread = new Thread(new ParameterizedThreadStart(this.Run));
- thread.Start(complatePort);
- }
- /// <summary>
- /// 外部提交数据对象到队列
- /// </summary>
- /// <param name="data"></param>
- public void Post(object data)
- {
- PostData(new PoolData(data));
- }
- /// <summary>
- /// 线程池主线程执行逻辑
- /// </summary>
- /// <param name="CompletionPortID"></param>
- private void Run(object CompletionPortID)
- {
- SafeFileHandle completionPort = (SafeFileHandle)CompletionPortID;
- while (IsOpened)
- {
- uint num;
- IntPtr intPtr;
- IntPtr value;
- //从队列里取出最前面的对象
- GetQueuedCompletionStatus(completionPort, out num, out intPtr, out value, 4294967295u);
- if (num > 0u)
- {
- GCHandle gCHandle = GCHandle.FromIntPtr(value);
- PoolData poolData = (PoolData)gCHandle.Target;
- gCHandle.Free();
- if (poolData.Command != PoolCommand.Command)
- {
- IsOpened = false;
- break;
- }
- RaiseExecute(poolData.Data);
- }
- }
- RaiseExitExecute("线程池已经停止。");
- isOpened = false;
- thread = null;
- }
- /// <summary>
- /// 触发Execute事件
- /// </summary>
- /// <param name="data"></param>
- private void RaiseExecute(object data)
- {
- Exceute?.Invoke(data);
- }
- /// <summary>
- /// 触发ExitExecute事件
- /// </summary>
- /// <param name="data"></param>
- private void RaiseExitExecute(object data)
- {
- ExitExceute?.Invoke(data);
- }
- /// <summary>
- /// 结束线程池主线程
- /// </summary>
- public void Stop()
- {
- PostData(new PoolData(PoolCommand.Exit));
- IsOpened = false;
- }
- /// <summary>
- /// 内部提交数据到线程池队列中
- /// </summary>
- /// <param name="data"></param>
- private void PostData(PoolData data)
- {
- if (complatePort.IsClosed)
- {
- return;
- }
- GCHandle value = GCHandle.Alloc(data);
- PostQueuedCompletionStatus(complatePort, (uint)IntPtr.Size, IntPtr.Zero, GCHandle.ToIntPtr(value));
- }
- public void Dispose()
- {
- if (thread != null && thread.ThreadState != ThreadState.Stopped)
- {
- Stop();
- }
- }
- }
- private CoreThreadPool pool = new CoreThreadPool();
- private CoreThreadPool poolExt = new CoreThreadPool();
- ...
- pool.Exceute += Pool_Exceute;
- pool.Start();
- poolExt.Exceute += PoolExt_Exceute;
- poolExt.Start()
- private void Pool_Exceute(object obj)
- {
- var entity = obj as UserInfo;
- if (entity == null) return;
- try
- {
- #region TODO本地防止重复请求
- using (DefaultDbContext db = new DefaultDbContext())
- {
- var dbEntity = db.Attenducelog.Where(e => e.Emp_No == entity.EmpNo).First();
- DateTime dt;
- if (dbEntity == null)
- {
- //第一次考勤
- dbEntity = new Attenducelog_Entity();
- dbEntity.Emp_No = entity.EmpNo;
- dt = DateTime.Now.AddDays(-1);
- dbEntity.Log_DateTime = dt;
- db.Attenducelog.Add(dbEntity);
- db.SaveChanges();
- }
- else
- {
- //已经多次考勤
- dt = dbEntity.Log_DateTime;
- }
- TimeSpan ts = DateTime.Now - dt;
- if (ts.TotalSeconds < 61)
- {
- return;
- }
- else
- {
- //已经多次考勤,本次成功了才记录打卡时间
- dbEntity = db.Attenducelog.Where(e => e.Emp_No == entity.EmpNo).First();
- dbEntity.Log_DateTime = DateTime.Now;
- db.Attenducelog.Update(dbEntity);
- db.SaveChanges();
- }
- }
- #endregion
- string url = $"{config.AppSettings.Settings["Platform"].Value}/business/attendancedetails/AddAttendanceDetails";
- #region dto
- PlatAttendanceDto dto = new PlatAttendanceDto();
- dto.KeyId = Guid.NewGuid().ToString();
- dto.Status = 0;
- dto.AuditDate = DateTime.Now.ToString("yyyy-MM-dd");
- dto.CreateBy = "AttendanceClient";
- dto.AttendanceDatetime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- dto.FkStore = config.AppSettings.Settings["StoreID"].Value;
- dto.EmpName = entity.Name;
- dto.EmpNo = entity.EmpNo;
- dto.WorkShift = "";
- dto.LocalDatetime = DateTime.Now;
- #endregion
- string jsonData = JsonConvert.SerializeObject(dto);
- string rs = Program.PostJsonData(url, jsonData);
- if (!string.IsNullOrEmpty(rs) && JObject.Parse(rs).Value<int>("code").Equals(200))
- {
- JObject rs_Object = JObject.Parse(rs);
- string data = rs_Object["data"].ToString();
- JObject log = JObject.Parse(data);
- string sound_TIPS = log.Value<string>("remark").Split("&".ToCharArray()).LastOrDefault();
- string tips = "[" + entity.Name + "] " + log.Value<string>("remark").Split("&".ToCharArray()).LastOrDefault();
- AppSpVoiceSpeak(sound_TIPS);
- MessageTip.ShowOk(tips, 3000);
- }
- }
- catch (Exception ex)
- {
- if (ex.Message.Contains("无法连接到远程服务器"))
- {
- Thread.Sleep(100);
- ViewFaceCore.Controls.MessageTip.ShowError("无法连接到远程服务器" + Environment.NewLine + "Unable to connect to remote server", 300);
- }
- }
- finally
- {
- Thread.Sleep(100);
- }
- }
- /// <summary>
- /// 持续检测一次人脸,直到停止。
- /// </summary>
- /// <param name="token">取消标记</param>
- private async void StartDetector(CancellationToken token)
- {
- List<double> fpsList = new List<double>();
- double fps = 0;
- Stopwatch stopwatchFPS = new Stopwatch();
- Stopwatch stopwatch = new Stopwatch();
- isDetecting = true;
- try
- {
- if (VideoPlayer == null)
- {
- return;
- }
- if (token == null)
- {
- return;
- }
- while (VideoPlayer.IsRunning && !token.IsCancellationRequested)
- {
- try
- {
- if (CheckBoxFPS.Checked)
- {
- stopwatch.Restart();
- if (!stopwatchFPS.IsRunning)
- { stopwatchFPS.Start(); }
- }
- Bitmap bitmap = VideoPlayer.GetCurrentVideoFrame(); // 获取摄像头画面
- if (bitmap == null)
- {
- await Task.Delay(10, token);
- FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
- continue;
- }
- if (!CheckBoxDetect.Checked)
- {
- await Task.Delay(1000 / 60, token);
- FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
- continue;
- }
- List<Models.FaceInfo> faceInfos = new List<Models.FaceInfo>();
- using (FaceImage faceImage = bitmap.ToFaceImage())
- {
- var infos = await faceFactory.Get<FaceTracker>().TrackAsync(faceImage);
- for (int i = 0; i < infos.Length; i++)
- {
- Models.FaceInfo faceInfo = new Models.FaceInfo
- {
- Pid = infos[i].Pid,
- Location = infos[i].Location
- };
- if (CheckBoxFaceMask.Checked || CheckBoxFaceProperty.Checked)
- {
- Model.FaceInfo info = infos[i].ToFaceInfo();
- if (CheckBoxFaceMask.Checked)
- {
- var maskStatus = await faceFactory.Get<MaskDetector>().PlotMaskAsync(faceImage, info);
- faceInfo.HasMask = maskStatus.Masked;
- }
- if (CheckBoxFaceProperty.Checked)
- {
- FaceRecognizer faceRecognizer = null;
- if (faceInfo.HasMask)
- {
- faceRecognizer = faceFactory.GetFaceRecognizerWithMask();
- }
- else
- {
- faceRecognizer = faceFactory.Get<FaceRecognizer>();
- }
- var points = await faceFactory.Get<FaceLandmarker>().MarkAsync(faceImage, info);
- float[] extractData = await faceRecognizer.ExtractAsync(faceImage, points);
- UserInfo userInfo = CacheManager.Instance.Get(faceRecognizer, extractData);
- if (userInfo != null)
- {
- faceInfo.Name = userInfo.Name;
- faceInfo.Age = userInfo.Age;
- switch (userInfo.Gender)
- {
- case GenderEnum.Male:
- faceInfo.Gender = Gender.Male;
- break;
- case GenderEnum.Female:
- faceInfo.Gender = Gender.Female;
- break;
- case GenderEnum.Unknown:
- faceInfo.Gender = Gender.Unknown;
- break;
- }
- pool.Post(userInfo);
- }
- else
- {
- faceInfo.Age = await faceFactory.Get<AgePredictor>().PredictAgeAsync(faceImage, points);
- faceInfo.Gender = await faceFactory.Get<GenderPredictor>().PredictGenderAsync(faceImage, points);
- }
- }
- }
- faceInfos.Add(faceInfo);
- }
- }
- using (Graphics g = Graphics.FromImage(bitmap))
- {
- #region 绘制当前时间
- StringFormat format = new StringFormat();
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Center;
- g.DrawString($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", new Font("微软雅黑", 32), Brushes.White, new Rectangle(0, 0, Width - 32, 188), format);
- g.DrawString($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", new Font("微软雅黑", 32), Brushes.White, new Rectangle(2, 2, Width - 32, 188), format);
- #endregion
- // 如果有人脸,在 bitmap 上绘制出人脸的位置信息
- if (faceInfos.Any())
- {
- g.DrawRectangles(new Pen(Color.Red, 4), faceInfos.Select(p => p.Rectangle).ToArray());
- if (CheckBoxDetect.Checked)
- {
- for (int i = 0; i < faceInfos.Count; i++)
- {
- StringBuilder builder = new StringBuilder();
- if (CheckBoxFaceProperty.Checked)
- {
- if (!string.IsNullOrEmpty(faceInfos[i].Name))
- {
- builder.Append(faceInfos[i].Name);
- }
- }
- if (builder.Length > 0)
- {
- g.DrawString(builder.ToString(), new Font("微软雅黑", 32), Brushes.White, new PointF(faceInfos[i].Location.X + faceInfos[i].Location.Width + 24, faceInfos[i].Location.Y));
- g.DrawString(builder.ToString(), new Font("微软雅黑", 32), Brushes.White, new PointF(faceInfos[i].Location.X + faceInfos[i].Location.Width + 24 + 2, faceInfos[i].Location.Y + 2));
- }
- }
- }
- }
- if (CheckBoxFPS.Checked)
- {
- stopwatch.Stop();
- if (numericUpDownFPSTime.Value > 0)
- {
- fpsList.Add(1000f / stopwatch.ElapsedMilliseconds);
- if (stopwatchFPS.ElapsedMilliseconds >= numericUpDownFPSTime.Value)
- {
- fps = fpsList.Average();
- fpsList.Clear();
- stopwatchFPS.Reset();
- }
- }
- else
- {
- fps = 1000f / stopwatch.ElapsedMilliseconds;
- }
- g.DrawString($"{fps:#.#} FPS", new Font("微软雅黑", 24), Brushes.Green, new Point(10, 10));
- }
- }
- FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
- }
- catch (TaskCanceledException)
- {
- break;
- }
- catch { }
- }
- }
- catch (Exception ex)
- {
- Program.AppLogger.Error(ex);
- }
- finally
- {
- isDetecting = false;
- }
- }