首页 > 系统相关 >我在winform项目里使用“Windows I/O完成端口”的经验分享

我在winform项目里使用“Windows I/O完成端口”的经验分享

时间:2024-02-22 12:24:02浏览次数:50  
标签:IntPtr dto Windows 端口 faceInfos new data public winform

少年!看你骨骼惊奇,是万中无一的练武奇才,我这儿有本武林秘籍,见与你有缘就送你了! 

如来神掌

Windows I/O完成端口是一个我至今都说不好的话题,请宽容的接受我这不是科班出身的自学成才的野生程序员身份。以前在上海一公司做产品追溯的时候,我的老大拿出一本《Windows核心编程》经常向我吹嘘什么“ Windows I/O完成端口”编程模型的时候我是云里雾里。后来看了公司常用的一个叫“线程池”的类的源码,豁然有点醒悟了,不就是类似Queue这样的东西么?按先进先出顺序处理业务数据,这明明就不是线程池啊,误导人了。但是这个类确实挺好用的,公司它都使用了很多年了。不想独享特此分享出来。

    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();
            }
        }
    }

 

第1001次实践体验过程

 

上次做的人脸考勤程序在处理多个人同时考勤时我就使用了刚刚的类。

  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;
            }
        }

其实触发数据就一句代码,看起来像这样:pool.Post(userInfo);

好了,高手请看笑话吃瓜,有需要的同学可亲自尝试。bye 了个 bye!

标签:IntPtr,dto,Windows,端口,faceInfos,new,data,public,winform
From: https://www.cnblogs.com/datacool/p/18027003/CoolThearPool

相关文章

  • Invicti v24.2.0 for Windows - 企业应用安全测试
    Invictiv24.2.0forWindows-企业应用安全测试InvictiStandard20Feb2024v24.2.0.43677请访问原文链接:https://sysin.org/blog/invicti/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgInvicti是一种自动化但完全可配置的Web应用程序安全扫描程序,使您能够......
  • Qt QWindowsWindow::setGeometryDp: Unable to set geometry问题
    总结原因:由于子窗口和父窗口的大小关系不健康,导致父窗口resize失败,失败后会自定义大小解决方法:首先,修改父窗口尺寸,保证其大小可以容纳子部件,可以使用setFixSize()之类的函数修改父窗口尺寸。其次,一定要保证修改父窗口尺寸的函数是放在窗口布局代码之前,如图,我的setIn......
  • Qt 颜色对话框QColorDialog弹出时应用程序输出栏出现QWindowsWindow::setGeometry: Un
    引言在项目中点击按钮,弹出颜色选择对话框,但同时应用程序会在应用程序输出一栏中显示QWindowsWindow::setGeometry:Unabletosetgeometry180x30+345+311(frame:202x86+334+266)onQWidgetWindow/"QColorDialogClassWindow"on"\\.\DISPLAY1".Resultinggeometry:5......
  • windows安装bun.js
    1.下载bun可执行文件,地址如下https://github.com/oven-sh/bun/releases/download/canary/bun-windows-x64.zip 2.解压到D盘修改文件夹名为bun并且创建快捷方式 3.增加环境变量 4.验证  bun--help&bun-v......
  • WinRT: 可能是 Windows 上最好用的 Native ABI 和远程调用方案
    前言Windows自从很久以来就有一个叫做COM的NativeABI。这是一套面向对象的ABI,在此之上Windows基于COMABI暴露了各种各样的API,例如ManagementAPI、ShellAPI和DirectXAPI就是典型。COM自然不仅局限于进程内调用,跨进程的RPC调用也是不在话下。但无论如何,COM......
  • 同一台Windows中使用IIS配置了多个SSL,须勾选「需要服务器名称指示」
    如果在同一台Windows中使用IIS配置了多个SSL,须勾选「需要服务器名称指示」,如下图。否则将会导致SSL错乱,具体表现是「手动配置一个SSL,会覆盖多个站点」。参考资料:https://www.51-n.com/t-4687-1-1.html至少一个其他网站正在使用同一HTTPS绑定,而此绑定用另一个证书配置。确......
  • Windows10在启动时自动运行的应用
    Windows10在启动时自动运行的应用步骤:选择“开始”按钮,然后滚动查找你希望在启动时运行的应用。右键单击该应用,选择“更多”,然后选择“打开文件位置”。此操作会打开保存应用快捷方式的位置。如果没有“打开文件位置”选项,这意味着该应用无法在启动时运行。文件位置打......
  • Windows环境使用ffmpeg转换文件格式
    先安装ffmpeg,官网下载地址https://ffmpeg.org/download.html直接保存即可 将命令保存为.bat 格式,放到ffmpeg.exe所在文件夹, 将所需转换的文件也放到该文件夹,双击bat文件运行即可1.flv 转mp4@echoofffor%%iin("*.flv")doffmpeg-i"%%i"-ccopy"%%i".mp4 ......
  • Windows 批处理(bat) if条件判断语句使用教程
    基本描述在bat脚本中,if条件判断语句共有6种比较操作符,分别为其中,只有等于操作符可以使用符号“==”表示,其他操作符只能使用英文简写当参与比较的字符串是字符串时,将被转换为对于的ASCII码进行比较If指令基本格式指令格式为:if条件表达式(…)注意:英文缩写的比较操作符,左......
  • 将SquareLine Studio导出的LVGL代码在windows上运行
    1.引入SDL驱动SquareLineStudio导出的LVGL代码后如果要在windows上运行需要引入SDL的驱动,官方导出的代码是没有的,这里提供一个自己在网上找到的SDL2-2.28.1包,解压后放在同一目录下即可2.编写CmakeLists.txt这里提供我这边自己修改的CmakeLists.txtcmake_minimum_required(......