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

Mutex 进程间互斥的更多相关文章

  1. pthread mutex 进程间互斥锁实例

    共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...

  2. linux 进程间同步互斥

    参考链接: https://www.oschina.net/code/snippet_237505_8646 http://www.cnblogs.com/xilentz/archive/2012/1 ...

  3. Operating System-进程间互斥的方案-保证同一时间只有一个进程进入临界区(3)- TSL指令

    本文接上一篇文章继续介绍如何实现同一时间只允许一个进程进入临界区的机制.本文主要介绍TSL指令. 方案汇总 屏蔽中断 锁变量 严格轮换法 TSL指令 Peterson解法 一.What is TSL ...

  4. Operating System-进程间互斥的问题-生产者&&消费者引入

    之前介绍的几种解决进程间互斥的方案,不管是Peterson方案还是TSL指令的方式,都有一个特点:当一个进程被Block到临界区外面时,被Block的进程会一直处于忙等待的状态,这个不但浪费了CPU资 ...

  5. C#使用互斥量(Mutex)实现多进程并发操作时进程间的同步操作(进程同步)

    本文主要是实现操作系统级别的进程同步的代码及测试结果,代码经过测试,可直接使用,也可供参考. 承接上一篇博客的业务场景[C#使用读写锁三行代码简单解决多线程并发写入文件时线程同步的问题]. 随着服务进 ...

  6. 使用 Mutex 实现进程间同步

    我们知道 Mutex 互斥量是可以用在线程间同步的,线程之间共享进程的数据,mutex 就可以直接引用.而进程有自己独立的内存空间,要怎样将它应用在进程间同步呢?为了达到这一目的,可以在 pthrea ...

  7. python并发编程之多进程1--(互斥锁与进程间的通信)

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  8. python并发编程之多进程1互斥锁与进程间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  9. NET多线程之进程间同步锁Mutex

    Mutex类似于lock.Monitor,都是为了解决多线程环境下,资源竞争导致的访问顺序问题.常见资源竞争有以下情况: 1.单例,如何确保单例: 2.IO文件操作,如果同时又多个线程访问同一个文件会 ...

随机推荐

  1. 【计算几何】【分类讨论】Gym - 101173C - Convex Contour

    注意等边三角形的上顶点是卡不到边界上的. 于是整个凸包分成三部分:左边的连续的三角形.中间的.右边的连续的三角形. 套个计算几何板子求个三角形顶点到圆的切线.三角形顶点到正方形左上角距离啥的就行了,分 ...

  2. [bzoj1011](HNOI2008)遥远的行星(近似运算)

    Description 直 线上N颗行星,X=i处有行星i,行星J受到行星I的作用力,当且仅当i<=AJ.此时J受到作用力的大小为 Fi->j=Mi*Mj/(j-i) 其中A为很小的常量, ...

  3. XCode6 ,iOS之PCH文件配置

    1: 创建PCH文件 NewFile-->Other中的PCH File-->Next-->Create 2:配置PCH文件 项目中的TARGETS-->Build Setti ...

  4. CentOS更新Python版本,同时修复yum不能使用的问题

    转自:Li_Hanx博客 遇到问题,需要更新python,网上找了好多都不能顺利更新,找到这位大佬的这篇博客,写的非常好,分享给大家. 发现一个新办法,那就是直接安装另一个版本的Python,比如Py ...

  5. c# 简单又好用的四舍五入方法

    http://www.soaspx.com/dotnet/csharp/csharp_20100415_3809.html四舍五入是软件开发中经常遇到的问题,我也在不止一个项目中用到这方面的运算:关于 ...

  6. MySQL优化之如何了解SQL的执行频率

    http://www.jb51.net/article/50180.htm show [session|global] status 可以根据需要加上参数“ session ”或者“ global ” ...

  7. AppCan入门教程

    主干 主干可以认为是整个页面的整体框架布局 上图是截取与ZAKER(原生开发).正益无线(HTML5开发).ZAKER微博界面(原生开发)和HTML5中国(HTML5开发).参考上述界面我们看到大部分 ...

  8. 【maven】pom.xml文件没错,但是项目有小红叉,Problems中可以看到错误:“Dynamic Web Module 3.0 requires Java 1.6 or newer.”

    解决方法: 1.将 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>m ...

  9. RRGGBBAA或者RRGGBB转换成rgba()

    //十六进制颜色值的正则表达式 var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; /*16进制颜色转为RGB格式*/ var colorRgb = fun ...

  10. Unity3D新手教学,让你十二小时,从入门到掌握!(二) [转]

    版权声明:本文为Aries原创文章,转载请标明出处.如有不足之处欢迎提出意见或建议,联系QQ531193915 继续上一讲的内容,首先呢, 为了接下来要做的小游戏,在这里我要小小的修改一下移动的代码. ...