• Mutex 进程间互斥


    学习Mutex的心得,不一定对,先记录一下。

    同步技术分为两大类,锁定和信号同步。

    锁定分为:Lock、Monitor

    信号同步分为:AutoResetEvent、ManualResetEvent、Semaphore以及Mutex。他们都继承自WaitHandle,

                       AutoResetEvent、ManualResetEvent在内存中维护一个布尔型变量,如果为false则阻塞,如果为true则解除阻塞

                       Semaphore在内存中维护一个整型变量,如果为0则阻塞,如果大于0则解除阻塞,每解除一个阻塞其值减一

    AutoResetEvent、ManualResetEvent、Semaph提供单进程内的线程同步

    Mutex提供跨应用程序域的线程阻塞和解除的能力,主要用于互斥访问。

    下面是一个使用Mutex进行互斥访问的演示例子。   

    软件打开时,如果接收到输入则创建一个互斥锁,并持有锁,直到再次接收到输入,然后释放锁,如果再次输入又创建锁,  如此循环。          

    假设app1创建一个互斥锁,然后持有锁,并对共享资源进行操作,那么app2就不能再次创建互斥锁,据此就能判断共享资源释放被别的进程占用。

    如果app1使用完了共享资源,释放了互斥锁,则app2就可以创建互斥锁,据此可以判断共享资源可以被访问了。

    以下是app1代码

    1、Mutex用于进程间的同步

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace MutexApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                new App1Class().write();
            }
        }
    
        class App1Class
        {
    
            public void write()
            {
                while (true)
                {
                    Console.WriteLine("please input a word to create mutex");
                    Console.WriteLine("");
                    Console.ReadLine();
                    //创建一个互斥锁,如果创建成功,则isCreate返回true
                    if (create())
                    {
                        Console.WriteLine("Application1 get the mutex 'test'");
                        Console.WriteLine("");
    
                        Console.WriteLine("please input a word to dispose mutex");
                        Console.WriteLine("");
    
                        //随便输入一个word,释放互斥锁
                        Console.ReadLine();
                        dispose();
                        Console.WriteLine("Application1 dispose mutex 'test'");
                        Console.WriteLine("");
    
                    }
                }
            }
    
            System.Threading.Mutex mutext = null;
            private bool create()
            {
                bool isCreate = false;
    //如果进程中没有名字为test的mutex,则创建成功isCreate为true,第一个参数如果为true,则指定创建mutex的线程拥有此mutex。 mutext = new System.Threading.Mutex(true, "test", out isCreate); if (!isCreate) { mutext.Dispose(); mutext = null; GC.Collect(); GC.WaitForPendingFinalizers(); } return isCreate; } private void dispose() { mutext.ReleaseMutex(); mutext.Dispose(); mutext = null; GC.Collect(); GC.WaitForPendingFinalizers(); } } }

    2、app2 代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                new App2Class().write();
            }
        }
    
        class App2Class
        {
    
            public void write()
            {
                while (true)
                {
                    Console.WriteLine("please input a word to create mutex");
                    Console.WriteLine("");
                    Console.ReadLine();
                    //创建一个互斥锁,如果创建成功,则isCreate返回true
                    if (create())
                    {
                        Console.WriteLine("Application2 get the mutex 'test'");
                        Console.WriteLine("");
    
                        Console.WriteLine("please input a word to dispose mutex");
                        Console.WriteLine("");
    
                        //随便输入一个word,释放互斥锁
                        Console.ReadLine();
                        dispose();
                        Console.WriteLine("Application2 dispose mutex 'test'");
                        Console.WriteLine("");
    
                    }
                }
            }
    
            System.Threading.Mutex mutext = null;
            private bool create()
            {
                bool isCreate = false;
                mutext = new System.Threading.Mutex(true, "test", out isCreate);
                if (!isCreate)
                {
                    mutext.Dispose();
                    mutext = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                return isCreate;
            }
    
            private void dispose()
            {
                mutext.ReleaseMutex();
                mutext.Dispose();
                mutext = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
    
        }
    }
    

      

    结果图:

     3、但是在实际应用中多用于单例模式,用于判断应用程序是否被创建。

                //单例模式
                bool bCreatedNew;
                System.Threading.Mutex mutex = new System.Threading.Mutex(false, Application.ProductName, out bCreatedNew);
                if (!bCreatedNew)
                {
                   //如果已经创建,则获取应用程序的句柄,并显示出来,或者提示已经运行
                    IntPtr hwnd = SingleProcess.FindWindow(null,Global.fromTitle);                            
                    SingleProcess.ShowWin(hwnd);
                    //SingleProcess.Singling("消息中心服务器");
                    //MessageBox.Show("打开失败,已有消息中心服务正在运行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WcfAlarmCenter
    {
        public class SingleProcess
        {
            //根据主窗体句柄显示窗体
            public static void ShowWin(IntPtr hwnd)
            {
                ShowWindow(hwnd, SW_RESTORE);
                SwitchToThisWindow(hwnd, true);
    
                Rect windowRec;
                GetWindowRect(hwnd, out windowRec);
                System.Drawing.Rectangle rect = System.Windows.Forms.SystemInformation.VirtualScreen;
                SetWindowPos(hwnd, HWND_TOP, (rect.Width - (windowRec.Right - windowRec.Left)) / 2,
                    (rect.Height - (windowRec.Bottom - windowRec.Top)) / 2, 0, 0, SWP_NOSIZE);
            }
    
            private static string _formText;// = string.Empty;
            private static Process _process = null;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="str"></param>
            public static void Singling(string formtext)
            {
                _formText = formtext;
                Process instance = GetInstance();
                if (instance != null)   //首先确定有无进程
                {
                    _process = instance;
                    if (_process.MainWindowHandle.ToInt32() != 0) //是否托盘化
                    {
                        //HandleRunningInstance(pro);
                        ShowWin(_process.MainWindowHandle);
                    }
                    else
                    {
                        CallBack myCallBack = new CallBack(Report);
                        EnumWindows(myCallBack, 0);
                    }
                    //System.Environment.Exit(System.Environment.ExitCode);
                }
    
            }
    
            public static Process GetInstance()
            {
                Process current = Process.GetCurrentProcess();
                Process[] processes = Process.GetProcessesByName(Application.ProductName);//current.ProcessName);
                //遍历正在有相同名字运行的例程    
                foreach (Process process in processes)
                {
                    //忽略现有的例程      
                    if (process.Id != current.Id)
                    {
                        //if (process.MainModule.FileName == current.MainModule.FileName)
                        {
                            //返回另一个例程实例          
                            return process;
                        }
                    }
                }
                //没有其它的例程,返回Null    
                return null;
            }
    
            private static bool Report(IntPtr hwnd, int lParam)
            {
                //获得窗体标题
                StringBuilder sb = new StringBuilder(100);
                GetWindowText(hwnd, sb, sb.Capacity);
    
                int calcID;
                //获取进程ID   
                GetWindowThreadProcessId(hwnd, out calcID);
                if ((sb.ToString() == _formText) && (_process != null) && (calcID == _process.Id)) //标题栏、进程id符合
                //if (pro != null && calcID == pro.Id) //进程id符合
                {
                    ShowWin(hwnd);
                    return true;
                }
                return true;
    
    
            }
    
    
            #region  win32 API
            /// <summary>
            /// 获取窗体句柄
            /// </summary>,两个参数至少要知道一个
            /// <param name="lpClassName">窗体类名,可以通过Spy++获取,为null表示忽略</param>
            /// <param name="lpWindowName">窗体标题,Text属性,为null时表示忽略</param>
            /// <returns></returns>
            [DllImport("user32.dll", EntryPoint = "FindWindow")]
            public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            /// <summary>
            /// 根据窗体句柄获得窗体标题
            /// </summary>
            /// <param name="hWnd"></param>
            /// <param name="lpText"></param>
            /// <param name="nCount"></param>
            /// <returns></returns>
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);
    
            /// <summary>
            /// 枚举窗体
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            [DllImport("user32")]
            private static extern int EnumWindows(CallBack x, int y);
            private delegate bool CallBack(IntPtr hwnd, int lParam);
    
            /// <summary>
            /// 根据窗体句柄获得其进程ID
            /// </summary>
            /// <param name="hwnd"></param>
            /// <param name="ID"></param>
            /// <returns></returns>
            [DllImport("User32.dll", CharSet = CharSet.Auto)]
            private static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
    
            /// <summary>
            /// 修改位置、大小
            /// </summary>
            /// <param name="hWnd"></param>
            /// <param name="hWndInsertAfter"></param>
            /// <param name="X"></param>
            /// <param name="Y"></param>
            /// <param name="cx"></param>
            /// <param name="cy"></param>
            /// <param name="uFlags"></param>
            /// <returns></returns>
            [DllImport("user32.dll")]
            private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
            /// <summary>
            ///     Retains the current size (ignores the cx and cy parameters).
            /// </summary>
            static uint SWP_NOSIZE = 0x0001;
            static int HWND_TOP = 0;
            public struct Rect
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
    
            [DllImport("user32.dll")]
            private static extern int GetWindowRect(IntPtr hwnd, out  Rect lpRect);
    
            /// <summary>
            /// 显示窗体,同  ShowWindowAsync 差不多
            /// </summary>
            /// <param name="hwnd"></param>
            /// <param name="nCmdShow"></param>
            /// <returns></returns>
            [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
            private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
            private const int SW_RESTORE = 9;
    
    
            /// <summary> 
            /// 该函数设置由不同线程产生的窗口的显示状态。 (没用)
            /// </summary> 
            /// <param name="hWnd">窗口句柄</param> 
            /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param> 
            /// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。</returns> 
            [DllImport("User32.dll")]
            private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
    
            /// <summary> 
            /// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。
            /// 键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。 
            /// (没用)
            /// </summary> 
            /// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param> 
            /// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。</returns> 
            [DllImport("User32.dll")]
            private static extern bool SetForegroundWindow(IntPtr hWnd);
            private const int WS_SHOWNORMAL = 1;
    
            /// <summary>
            /// 窗体焦点
            /// </summary>
            /// <param name="hWnd"></param>
            /// <param name="fAltTab"></param>
            [DllImport("user32.dll ", SetLastError = true)]
            private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    
            #endregion
    
    
    
        }
    }
    

      

    参考

    http://www.cnblogs.com/city22/archive/2007/02/02/638260.html

    信号量与互斥锁

    C# 多线程之一:信号量Semaphore

    C#多线程之二:ManualResetEvent和AutoResetEvent

  • 相关阅读:
    认识 liunx 文件属性
    laravel 配置mongodb 出现 Database [text] not configured 问题【已解决】
    php 判断字符串的长度的两种方法
    php 循环里面套sql怎么解决
    php 给入门新手们填的第一个坑
    Vue 调用其他Vue或自己Vue中的方法时,this指向不生效
    绑定点击事件触发多次
    computed 计算属性的获取和设置
    el-Cascader 最后一项删不掉
    前端 --- 格式化的配置
  • 原文地址:https://www.cnblogs.com/xiaochun126/p/5133322.html
Copyright © 2020-2023  润新知