C# mutex互斥锁构造

概念

      Mutex出现的比monitor更早,而且传承自COM,当然,waitHandle也是它的父类,它继承了其父类的功能,有趣的是Mutex的脾气非常的古怪,它

允许同一个线程多次重复访问共享区但是对于别的线程那就必须等待,同时,它甚至支持不同进程中的线程同步,这点更能体现他的优势,但是劣势也是显而

易见的,那就是巨大的性能损耗和容易产生死锁的困扰,所以除非需要在特殊场合,否则 我们尽量少用为妙,这里并非是将mutex的缺点说的很严重,而是建议

大家在适当的场合使用更为适合的同步方式,mutex 就好比一个重量型的工具,利用它则必须付出性能的代价。

重点

1、Mutex 相比信号量增加了所有权的概念,一只锁住的 Mutex 只能由给它上锁的线程解开,只有系铃人才能解铃。Mutex 的功能也就因而限制在了构造临界区上。
2、是重入锁,内部有个递归计数器,每次调用都会导致计数器增加1,releaseMutex 导致计数器-1。计数器为0时其他线程才能使用该互斥锁。
mutex 递归问题,导致互斥锁多次进入 内核,所有性能不是很好。可以用autoresetevent 来实现互斥锁的功能。

什么是可重入锁当一个线程获取锁时,如果没有其它线程拥有这个锁,那么,这个线程就成功获取到这个锁。之后,如果其它线程再请求这个锁,就会处于阻塞等待的状态。但是,如果拥有这把锁的线程再请求这把锁的话,不会阻塞,而是成功返回,所以叫可重入锁。只要你拥有这把锁,你可以可着劲儿地调用,比如通过递归实现一些算法,调用者不会阻塞或者死锁。Mutex 不是可重入的锁。Mutex 的实现中没有记录哪个 goroutine 拥有这把锁。理论上,任何 goroutine 都可以随意地 Unlock 这把锁,所以没办法计算重入条件。

3、Mutex是一个内核对象,所以,它是可以用作跨进程线程同步的,进程间互斥。。

A进程可以如此写:

Mutex mutex = new Mutex(true,"mutex1");

B进程则可以如此写:

Mutex mutex = Mutex.OpenExisting("mutex1")
OpenExisting这个方法签名我们后面也可以经常看到,作用就是获取一个已经存在的内核对象。
获取到之后的线程同步代码是跟单进程是一致的。

mutex 递归案例

//mutex 递归问题,导致互斥锁多次进入 内核,所有性能不是很好。可以用autoresetevent 来实现互斥锁的功能。
Mutex mutex = new Mutex(false, "first");

Thread threada = new(A);
Thread threadB = new(B);
threada.Start();
threadB.Start();

void A(){
    mutex.WaitOne();
    Console.WriteLine("I am A method");
   
    Console.WriteLine("A call B method");
    B();    
    mutex.ReleaseMutex();   
    }


void B()
{
    mutex.WaitOne();
    Console.WriteLine("I am B method");
    mutex.ReleaseMutex();
}/*
输出:
I am A method
A call B method
I am B method
I am B method*/

  用AutoResetEvent实现一个类似于metux的锁。

AutoMutex am=new AutoMutex();
for (int i = 0; i < 10; i++)
{
    new Thread(() => {
        am.Enter();
        
        Thread.Sleep(1000);
        am.Release();

    }).Start();
}

class AutoMutex
{

   static AutoResetEvent are =new AutoResetEvent(true);
    static int lockOwner=-1;//当前锁的拥有者
    static int recursionCount=-1;//迭代计数器
 
    public void Enter()
    {
       int currentcount = Environment.CurrentManagedThreadId;
        if (lockOwner == currentcount)
        {
             
            recursionCount++;
            return;
        }

      
        are.WaitOne();
        Console.WriteLine("Current Thread{0}", Environment.CurrentManagedThreadId);
        recursionCount = 1;
        lockOwner = currentcount;
    }
    public void Release()
    {
        if (lockOwner == Environment.CurrentManagedThreadId) return;
        if(--recursionCount == 0)
        {
            are.Set();
            lockOwner = -1;
        }
    


    }

    public void Dispose()
    {

        are.Close();
        are.Dispose();
    }

}

 

posted @ 2022-01-17 20:51  小林野夫  阅读(337)  评论(0编辑  收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/