c# - 同时获取多个线程同步锁

标签 c# multithreading locking c++-cli mutex

假设以下代码在我的应用程序中以类似的方式使用:

//-------------------------------------
void UseAllResources ()
{
  bool bSuccess1 = false;
  bool bSuccess2 = false;
  try
  {
    bSuccess1 = Monitor::TryEnter (oResource1, msc_iTimeoutMonitor);
    if (!bSuccess1) return;
    bSuccess2 = Monitor::TryEnter (oResource2, msc_iTimeoutMonitor);
    if (!bSuccess2) return;

    // work on oResource1 and oResource2
  } finally {
    if (bSuccess2)
      Monitor::Exit (oResource2);
    if (bSuccess1)
      Monitor::Exit (oResource1);
  }
}

//-------------------------------------
void UseResource1 ()
{
  bool bSuccess = false;
  try {
    bSuccess = Monitor::TryEnter (oResource1, msc_iTimeoutMonitor);
    if (!bSuccess) return;

    // work on oResource1
  } finally {
    if (bSuccess) Monitor::Exit (oResource1);
  }
}

//-------------------------------------
void UseResource2 ()
{
  same like UseResource1(), but using oResource2
}

这些函数可能随时被不同的线程调用。

可能会发生
(超时为500ms)
@t=0ms,线程B正在执行UseResource2(),需要400ms,
@t=100ms,线程 Z 正在调用 UseAllResources(),获取了 oResource1 上的锁,必须等待 oResource2 上的锁,
@t=200ms,线程 A 正在调用 UseResource1() 并且必须等待 oResource1 上的锁,它被线程 Z 占用,
@t=400ms,线程B完成,线程Z获取oResource2上的锁并开始工作,需要400ms,
@t=700ms,线程 A 超时,尽管它只需要 50 毫秒并且可以在线程 Z 仍在等待时工作。

我宁愿线程 Z 失败,如果有的话,因为超时应该是所有锁的总值。

我可以同时开始获取多个锁吗?

最佳答案

一个解决方案可能是使用 ReaderWriterLockSlim 类。下面的代码在构造函数中包装了一个函数(你要做的工作)。或者,您可以将该函数移至 DoWork 方法以更改您访问资源的方式。

LockedResource 实现

class LockedResource
{
    public delegate void RefAction();

    ReaderWriterLockSlim resourceLock;

    public LockedResource()
    {
        //Warning: SupportsRecursion is risky, you should remove support for recursive whenever possible
        resourceLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
    }

    public bool DoWork(RefAction work, string threadname, int timeout = -1)
    {
        try
        {
            if (resourceLock.TryEnterWriteLock(timeout))
            {
                if (work != null)
                {
                    work();
                }
            }
            else
            {
                Console.WriteLine("Lock time out on thread {0}", threadname);
            }
        }
        finally
        {

            Console.WriteLine("{0} releasing resource", threadname);
            if(resourceLock.IsWriteLockHeld)
            {
                resourceLock.ExitWriteLock();
            }
        }

        return false;
    }
}

示例用法

static void Main(string[] args)
{
        object oResouce1 = "-";
        object oResouce2 = "-";

        LockedResource lock1 = new LockedResource();
        LockedResource lock2 = new LockedResource();

       //the event wait handles is not required, only used to block thread so that resource values can be printed out at the end of the program
        var h1 = new EventWaitHandle(false, EventResetMode.ManualReset);
        var h2 = new EventWaitHandle(false, EventResetMode.ManualReset);
        var h3 = new EventWaitHandle(false, EventResetMode.ManualReset);

        WaitHandle[] waitHandles = { h1, h2, h3 };

        var t1 = new Thread(() =>
        {
            lock1.DoWork(() =>
            {
                oResouce1 = "1";
                Console.WriteLine("Resource 1 set to 1");
            },"T1");

            h1.Set();
        });

        var t2 = new Thread(() =>
        {
            lock2.DoWork(() =>
            {
                oResouce2 = "2";
                Console.WriteLine("Resource 2 set to 2");
                Thread.Sleep(10000);

            }, "T2");
            h2.Set();
        });

        var t3 = new Thread(() =>
        {
            lock1.DoWork(() =>
            {
                lock2.DoWork(() =>
                {
                    oResouce1 = "3";
                    Console.WriteLine("Resource 1 set to 3");

                    oResouce2 = "3";
                    Console.WriteLine("Resource 2 set to 3");
                }, "T3", 1000);
                h3.Set();

            },  "T3");

        });
        t1.Start();
        t2.Start();
        t3.Start();


        WaitHandle.WaitAll(waitHandles);
        Console.WriteLine("Resource 1 is {0}", oResouce1);
        Console.WriteLine("Resource 2 is {0}", oResouce2);

        Console.ReadLine();
}

输出

Resource 1 set to 1
Resource 2 set to 2
T1 releasing resource
Lock time out on thread T3
T3 releasing resource
T3 releasing resource
T2 releasing resource
Resource 1 is 1
Resource 2 is 2

关于c# - 同时获取多个线程同步锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37520451/

相关文章:

python - 在python中测试是否已经获取了锁

c# - WebApi 2.0 中的 MEF 未解析

java - 多个线程读取和导入目录中的文件

java - 通过具体(Java)示例进行乐观锁定

c# - 在 TPL 中安全添加集合

multithreading - +[NSThread detachNewThreadSelector :toTarget:withObject:] and -[NSObject performSelectorInBackground:withObject:]? 和有什么区别

mysql插入竞争条件

c# - 我的 IUserClaimsPrincipalFactory 实现导致 IdentityServer4 上出现 StackOverflowException

c# - 是否可以克隆 IEnumerable<T> 实例,保存迭代状态的副本?

c# - 从 WinForms 应用程序重新启动计算机?