• C#关于软件界面无响应、BUG报警、程序异常退出等情况的监控和报警


    对程序的监控,一般采用另外一个进程进行监控(即主进程和监控进程),主进程运行后,先查找下看有没有还在残留运行的监控进程,如果有先结束监控进程,然后重新启动。

    如何监控主程序的思路是:主程序中开辟一个共享内存映射文件,通过定时器向文件写入变化的信号数据(自定义)。监控程序定时从共享内存文件中读取信号数据,并和上次读取的信号数据进行对比,如果不一致表示主程序运行正常,如果不一致,表示运行异常或者程序异常退出。

    内存映射文件

    内存映射文件是由一个文件到进程地址空间的映射。

            C#提供了允许应用程序把文件映射到一个进程的函(MemoryMappedFile.CreateOrOpen)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。

            共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件。共享内存的主语是进程(Process),操作系统默认会给每一个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程的。而有时候需要在不同进程之间访问同一段内存,怎么办呢?操作系统给出了创建访问共享内存的API,需要共享内存的进程可以通过这一组定义好的API来访问多个进程之间共有的内存,各个进程访问这一段内存就像访问一个硬盘上的文件一样。而.Net 4.0中引入了System.IO.MemoryMappedFiles命名空间,这个命名空间的类对windows 共享内存相关API做了封装,使.Net程序员可以更方便的使用内存映射文件。

    内存映射文件实现进程间通讯

            内存映射文件是实现进程通讯的又一种方法,我们可以通过共享剪贴板、共享物理文件来实现进程间的数据共享,这里我们还可以通过内存映射文件来实现共享,这样,文件内的数据就可以用内存读/写指令来访问,而不是用ReadFile和WriteFile这样的I/O系统函数,从而提高了文件存取速度。这种方式更加快捷高效,最适用于需要读取文件并且对文件内包含的信息做语法分析的应用程序,如:对输入文件进行语法分析的彩色语法编辑器,编译器等。这种数据共享是让两个或多个进程映射同一文件映射对象的视图,即它们在共享同一物理存储页。这样,当一个进程向内存映射文件的一个视图写入数据时,其他的进程立即在自己的视图中看到变化。

    注意:

            对文件映射对象要使用同一名字。

            是让两个或多个进程映射同一文件映射对象的视图,即它们在共享同一物理存储页。这样,当一个进程向内存映射文件的一个视图写入数据时,其他的进程立即在自己的视图中看到变化。但要注意,对文件映射对象要使用同一名字。

    公用类:

     1 /// <summary>
     2     /// 进程间通讯,共享映射文件
     3     /// </summary>
     4     public class MappingHelper
     5     {
     6         long capacity = 1024 * 1024;
     7         public MemoryMappedFile file;
     8 
     9         public MappingHelper()
    10         {
    11         }
    12 
    13         public MappingHelper(string fileName,string mapName)
    14         {
    15             file = MemoryMappedFile.CreateFromFile(fileName,FileMode.OpenOrCreate,mapName,capacity);
    16         }
    17         
    18         /// <summary>
    19         /// 将消息写入共享映射文件
    20         /// </summary>
    21         /// <param name="msg">消息内容</param>
    22         public void WriteString(string msg)
    23         {
    24             using (var stream = file.CreateViewStream())
    25             {
    26                 using (var writer = new BinaryWriter(stream))
    27                 {
    28                     writer.Write(msg);
    29                 }
    30             }
    31         }
    32         /// <summary>
    33         /// 从共享映射文件中读取消息
    34         /// </summary>
    35         /// <returns></returns>
    36         public string ReadString()
    37         {
    38             using (var stream = file.CreateViewStream())
    39             {
    40                 using (var reader = new BinaryReader(stream))
    41                 {
    42                     List<byte> bytes = new List<byte>();
    43                     byte[] temp = new byte[1024];
    44                     while (true)
    45                     {
    46                         int readCount = reader.Read(temp, 0, temp.Length);
    47                         if (readCount == 0)
    48                         {
    49                             break;
    50                         }
    51                         for (int i = 0; i < readCount; i++)
    52                         {
    53                             bytes.Add(temp[i]);
    54                         }
    55                     }
    56                     if (bytes.Count > 0)
    57                     {
    58                         return Encoding.Default.GetString(bytes.ToArray()).Replace("\0", "");
    59                     }
    60                     else
    61                     {
    62                         return null;
    63                     }
    64                 }
    65             }
    66         }
    67     }
    View Code

    主程序:

     //将指定文件映射到内存中,监控进程读取时,要用一样的内存映射名
    _MappingHelper=new MappingHelper("path","内存中的映射名");
    //通过定时器定时写入变化的数据信号
    private void _Timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                _MappingHelper.WriteString(DateTime.Now.ToString("yyyyMMddHHmmss"));
            }
    View Code

    监控程序:

     1 public static void Main(string[] args)
     2         {
     3             try
     4             {
     5                 mhHelper.file = MemoryMappedFile.OpenExisting("主程序创建的内存映射文件名");
     6                 string laststr = "";
     7                 do
     8                 {                    
     9                      //读取被监控进程定时发送的数据
    10                     string tempstr = mhHelper.ReadString();
    11                     if (tempstr == laststr)//表示程序死机或异常退出
    12                     {
    13                         //此处进行异常处理..................
    14                         DisposeMemoryMapFile();
    15                         Process.GetCurrentProcess().Kill();
    16                     }
    17                     else
    18                     {
    19                         laststr = tempstr;
    20                     }
    21 
    22                     Thread.Sleep(2000);
    23                 }
    24                 while (true);
    25             }
    26             catch (Exception e)
    27             {
    28                 
    29             }
    30         }                        
    View Code
  • 相关阅读:
    Java并发包源码学习系列:基于CAS非阻塞并发队列ConcurrentLinkedQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedBlockingDeque源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedTransferQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之SynchronousQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
    Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析
    Java并发包源码学习系列:挂起与唤醒线程LockSupport工具类
  • 原文地址:https://www.cnblogs.com/BennyHua/p/11131039.html
Copyright © 2020-2023  润新知