互斥体与互锁 <第五篇>

互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码“临界区”。因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。

  任何线程在进入临界区之前,必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。什么时候需要使用互斥体呢?互斥体用于保护共享的易变代码,也就是,全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。

1、Mutex

  Mutex是一个同步基元,它与前面提到的锁最大的区别在于它支持进程间同步。

  Mutex允许同一个线程多次重复访问共享区,但是对于别的线程那就必须等待,它甚至支持不同进程中的线程同步,这点更能体现他的优势,但是劣势也是显而易见的,那就是巨大的性能损耗和容易产生死锁的困扰,所以除非需要在特殊场合,否则 我们尽量少用为妙,这里并非是将Mutex的缺点说的很严重,而是建议大家在适当的场合使用更为适合的同步方式,Mutex 就好比一个重量型的工具,利用它则必须付出性能的代价。

  1、Mutex线程同步

  Mutex实现线程同步主要依靠以下两个方法实现:

  • WaitOne 阻止当前线程,直到当前 WaitHandle 收到信号。
  • ReleaseMutex 释放 Mutex 一次。

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(Run);
            }

            Console.Read();
        }

        static int count = 0;

        static Mutex mutex = new Mutex();

        static void Run(object obj)
        {
            //阻止当前线程
            mutex.WaitOne();

            Console.WriteLine("当前数字:{0}", ++count);

            //释放 Mutex
            mutex.ReleaseMutex();
        }
    }

  输出:

  

  Mutex和Monitor的区别:

  1. Monitor不是waitHandle的子类,它具有等待和就绪队列的实际应用;
  2. Monitor无法跨进程中实现线程同步,但是Mutex可以;
  3. 相对而言两者有明显的性能差距,mutex相对性能较弱但是功能更为强大,monitor则性能比较好;
  4. 两者都是用锁的概念来实现同步不同的是monitor一般在方法(函数)调用方加锁;mutex一般在方法(函数)内部加锁,即锁定被调用端;

  2、进程间同步

  当给Mutex取名的时候能够实现进程同步,不取名实现线程同步。

  Mutex有两种类型:未命名的局部mutex和已命名的系统mutex。

  • 本地mutex仅存在与进程当中,进程内可见;
  • 已命名的系统mutex在整个操作系统中可见,可用于同步进程活动;

    class Program
    {
        static void Main(string[] args)
        {
            //使用线程输出等待状态
            Thread t1 = new Thread(ShowMyWord);
            t1.Start();

            Run(t1);

            Console.Read();
        }

        static int count = 0;

        static Mutex mutex = new Mutex(false, "xxoo");

     static void Run(Thread t1)
        {

            //这个WaitOne方法要么返回true,要么一直不返回(不会返回false),所以没办法用if来判断
            //于是,用个线程输出等待状态
            mutex.WaitOne();

            Console.WriteLine("终于轮到老子了!  " + DateTime.Now.TimeOfDay.ToString());
            //停止线程t1,不要再输出等待状态
            t1.Abort();
            //模拟干活十秒
            Thread.Sleep(10000);
            Console.WriteLine("干完!  " + DateTime.Now.TimeOfDay.ToString());

            //释放 Mutex
            mutex.ReleaseMutex();
        }

        static void ShowMyWord(object obj)
        {
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(2000);
                Console.WriteLine("我的心在等待,一直在等待!   " + DateTime.Now.TimeOfDay.ToString());
            }
        }
    }

  以上代码,将生成的.exe文件复制两份:

  

  快速运行两个输出如下:

  

二、Interlocked

  实际引用中,可能我们对共享变量的使用并不十分复杂,可能只是一些简单的操作如:自增、自减、求和、赋值、比较等。

  MSDN中的解析Interlocked为多个线程共享的变量提供原子操作。

  常用操作如下:

方法 说明
Add 相加
CompareExchange 比较
Increment 递增
Decrement 递减
Exchange 赋值

  示例:

   class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 20; i++)
            {
                Thread t = new Thread(Run);

                t.Start();
            }

            Console.Read();
        }

        static int Incre = 0;
        static int Add = 0;
        static int Exchange = 0;
        static int Decre = 21;
        static int CompareExchange = 0;

        static Mutex mutex = new Mutex();

        static void Run()
        {
            //自增操作
            //Console.WriteLine("当前数字:{0}", Interlocked.Increment(ref Incre));
            //递减操作
            //Console.WriteLine("当前数字:{0}", Interlocked.Decrement(ref Decre));
            //相加
            //Console.WriteLine("当前数字:{0}", Interlocked.Add(ref Add,10));
            //赋值
            //Console.WriteLine("当前数字:{0}", Interlocked.Exchange(ref Exchange, 5));
            //比较,如果第三个参数等于CompareExchange,则将第二个参数的值,赋给第一个参数
            Console.WriteLine("当前数字:{0}", Interlocked.CompareExchange(ref CompareExchange, 15,0));

        }
    }

时间: 2024-08-24 19:34:44

互斥体与互锁 <第五篇>的相关文章

信号量、互斥体和自旋锁

http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html 信号量.互斥体和自旋锁 一.信号量 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信.本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况.一般说来,为了获得共享资源,进程需要执行下列操作:  (1) 测试控制该资源的信号量.  (2) 若此信号量的值为正,则允许进行使用该资源.进程将信号量减1.

信号量、互斥体和自旋锁小结

概述 linuxn内核同步机制几种常用的方式,面试经常会被问道,这里做一个小结 [1]信号量 [2]互斥体 [3]自旋锁 [4]区别 1.信号量(semaphore) 又称为信号灯,本质上,信号量是一个计数器,用来记录对某个共享资源的存取情况,一般共享资源通过以下步骤 (1) 测试控制该资源的信号量(n). (2) 若此信号量的值为正,则允许进行使用该资源.进程将信号量减1. (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1). (4)

[转载] 《重要》内核下各种同步处理方法(自旋锁、信号灯、互斥体…)

本文转载自: http://www.blogfshare.com/kernel-synchronization.html 1.在支持多线程的操作系统下,有些函数会出现不可重入的现象.所谓“可重入”是指函数的执行结果不和执行顺序有关.反之如果执行结果和执行顺序有关,则称这个函数是“不可重入”的. 2.Windows将中断的概念进行了扩展,提出一个中断请求级(IRQL)的概念.其中规定了32个中断请求级别,分别是0~2级别为软件中断,3~31级为硬件中断,其中数字从0~31,优先级别逐次递增. 在内

秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题 在<秒杀多线程第九篇 经典线程同步总结 关键段 事件 互斥量 信号量>中对经典多线程同步互斥问题进行了回顾和总结,这篇文章对Windows系统下常用的线程同步互斥机制——关键段.事件.互斥量.信号量进行了总结.有网友问到互斥量能处理“遗弃”问题,事件和信号量是否也能处理“遗弃”问题.因此本文将对事件和信号量作个试验,看看事件和信号量能否处理“遗弃”问题. 一.

linux驱动之 信号量 自旋锁 互斥体

原子操作 原子操作就是单位操作,也就是说操作过程不能被中断 下面代码中每条语句看起来是原子操作,其实不是原子操作: int main(0 { int i=2;//两天汇编语句组成 i=i+3;//三条汇编语句组成 } 实现原子操作方法; 1  自旋锁 自旋锁它是为为实现保护共享资源而提出一种锁机制.其实,自旋锁与互斥锁比较类似 ,它们都是为了解决对某项资源的互斥使用.无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁.但是两者在调度机制上略

SOS 调试扩展 (SOS.dll) 《第五篇》

SOS调试扩展让你可以查看在公共语言运行时里面运行的代码的有关信息.例如,你可以使用SOS调试扩展显示托管堆的有关信息,查找堆的错误,显示运行时使用的内部数据类型,以及查看在运行时里面运行的所有托管代码的有关信息. 使用SOS调试扩展的办法是把它装入到WinDbg.exe调试器,或者Visual Studio 2005或它的更早版本.你能够在WinDgb.exe里或者在Visual Studio的即时窗口里面执行令来载入它. 在Windbg.exe中装载SOS的命令是: .loadby sos

[叩响C#之门]写给初学者:多线程系列(七)——互锁(Interlocked类)

前言:我第一次接触“线程”的概念时,觉得它深奥难懂,看了好多本书,花了很长时间才领悟到它的真谛.现在我就以一个初学者的心态,把我所理解的“多线程”描述给大家.这一次是系列文章,比较完整的展示与线程相关的基本概念.希望对初学者有所帮助.语言比较精炼,有些地方需要反复阅读. 目录(欲看前面的章节,请点击下面的链接 ) 第21章 多 线 程 21.1 线程的概念 21.2 Thread类 21.3 线程的优先级 21.4 线程的插入 21.5 线程的状态 21.6 线程的同步 21.6.1 线程同步的

互联网神经学系列第五篇:研究大脑中的谷歌,脸书和华为思科路由,脑互联网生理学

本文是互联网神经学系列第五篇-"大脑中的类互联网应用和结构,脑互联网生理学" 一.人类大脑研究的困境 大脑的秘密一直是科学皇冠上最明亮的宝石之一,但在两千年前,人们确连它的重要意义还不知道,例如著名的亚里士多德(Aristotle,公元前384-前322)认为神智在心,是心控制着我们的思想,情绪.大约公元前5世纪,地中海科斯岛上托名希波克拉底(Hippocrates)的一群医生被认为是最早发现了脑是神智的载体,在希波克拉底著作中有如下一段话."人们应当认识到:我们的愉悦.欢乐

用户模式同步之互斥体小解

1.互斥体(互斥体类似于同步事件)互斥体可避免多个线程争夺一个资源的问题,多线程环境下,如果一个线程获得互斥体,不释放的话其他的线程就获得不了该资源它与同步事件的区别:是在同一个线程内它可以递归获得互斥体,也就是这个线程获得互斥体后对再次去获得认可不排斥,同步我们显而易见的得知不允许这样他有激发未激发两种状态,记住!!!获得互斥体是未激发状态,释放互斥体是激发状态,他和信号量区别清楚同样使用它首先要初始化;CreateMutex(SECURITY,BOOL(是否被占有),LPCTSTR(name