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


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

    如来神掌

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
        public class CoreThreadPool : IDisposable
        {
            ///
            /// 队列元素申明
            ///
            [StructLayout(LayoutKind.Sequential)]
            private class PoolData
            {
                ///
                /// 外部要求放入队列的数据
                ///
                public object Data;
                ///
                /// 需要执行的命令(Exit/Command(自定义))
                ///
                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;
            ///
            /// 线程池主线程
            ///
            protected Thread thread;
            protected volatile bool isOpened;
            [method: CompilerGenerated]
            [CompilerGenerated]
            public event Action<object> Exceute;
            [method: CompilerGenerated]
            [CompilerGenerated]
            public event Action<object> ExitExceute;
            ///
            /// 线程池是否正在运行
            ///
            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);
            ///
            /// 启动线程池的主线程
            ///
            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);
            }
            ///
            /// 外部提交数据对象到队列
            ///
            ///
            public void Post(object data)
            {
                PostData(new PoolData(data));
            }
            ///
            /// 线程池主线程执行逻辑
            ///
            ///
            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;
            }
            ///
            /// 触发Execute事件
            ///
            ///
            private void RaiseExecute(object data)
            {
                Exceute?.Invoke(data);
            }
            ///
            /// 触发ExitExecute事件
            ///
            ///
            private void RaiseExitExecute(object data)
            {
                ExitExceute?.Invoke(data);
            }
            ///
            /// 结束线程池主线程
            ///
            public void Stop()
            {
                PostData(new PoolData(PoolCommand.Exit));
                IsOpened = false;
            }
            ///
            /// 内部提交数据到线程池队列中
            ///
            ///
            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);
        }
    }
    复制代码
    复制代码
            /// 
            /// 持续检测一次人脸,直到停止。
            /// 
            /// 取消标记
            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 faceInfos = new List();
                            using (FaceImage faceImage = bitmap.ToFaceImage())
                            {
                                var infos = await faceFactory.Get().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().PlotMaskAsync(faceImage, info);
                                            faceInfo.HasMask = maskStatus.Masked;
                                        }
                                        if (CheckBoxFaceProperty.Checked)
                                        {
                                            FaceRecognizer faceRecognizer = null;
                                            if (faceInfo.HasMask)
                                            {
                                                faceRecognizer = faceFactory.GetFaceRecognizerWithMask();
                                            }
                                            else
                                            {
                                                faceRecognizer = faceFactory.Get();
                                            }
                                            var points = await faceFactory.Get().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().PredictAgeAsync(faceImage, points);
                                                faceInfo.Gender = await faceFactory.Get().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!

  • 相关阅读:
    C/C++中的类型转换
    基于智能合约的银行借贷方案设计与实现
    c++ 类的特殊成员函数:移动构造函数(五)
    计算机毕业设计Java课程作业管理系统(源码+mysql数据库+系统+lw文档)
    40% 的云原生开发者专注于微服务领域
    基于MATLAB的高阶(两个二阶级联构成的四阶以及更高阶)数字图形音频均衡器系数计算(可直接用于DSP实现)
    斑馬打印機打印中文
    IIS之WEB服务器
    微信小程序中自定义模板
    Mysql 死锁和死锁的解决方案
  • 原文地址:https://www.cnblogs.com/datacool/p/18027003/CoolThearPool