信号量与互斥锁

故事扮演 提交于 2019-12-25 03:01:19

学习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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!