C# 多个任务中的一个任务获得互斥锁的时间比其他任务长得多

C# 多个任务中的一个任务获得互斥锁的时间比其他任务长得多,c#,multithreading,concurrency,task-parallel-library,mutex,C#,Multithreading,Concurrency,Task Parallel Library,Mutex,形势 目前在我的项目中,我有3个Workers内部有一个工作循环,还有一个CommonWork类对象,它包含Work方法(DoFirstTask、DoSecondTask、DoThirdTask),Workers可以调用这些方法。每个工作方法必须相互排斥地执行。每种方法都会产生更多嵌套的任务,这些任务会一直等到完成 问题 当所有3名Worker都启动时,2名Worker以相同的速度运行,但第3名Worker落后于或1名Worker速度非常快,第2名稍慢,第3名非常慢,这取决于现实世界 奇异性 当

形势

目前在我的项目中,我有3个
Workers
内部有一个工作循环,还有一个
CommonWork
类对象,它包含
Work
方法(DoFirstTask、DoSecondTask、DoThirdTask),Workers可以调用这些方法。每个
工作
方法必须相互排斥地执行。每种方法都会产生更多嵌套的
任务
,这些任务会一直等到完成

问题

当所有3名
Worker
都启动时,2名
Worker
以相同的速度运行,但第3名
Worker
落后于1名
Worker
速度非常快,第2名稍慢,第3名非常慢,这取决于现实世界

奇异性

当只有两个
工人
在工作时,他们也会很好地分担工作,并以相同的速度工作

更有趣的是,即使是第三个
Worker
调用的
CommonWork
方法数量更少,并且有可能执行更多的循环,但事实并非如此。我试着在下面的代码中模拟这个条件:

if (Task.CurrentId.Value < 3)

解决方案是使用
新的SempahoreSlim(1)
而不是
互斥锁
(或简单的
,或
监视器
)。仅使用
SemaphoreSlim
使
线程调度
成为循环,因此没有使某些线程/任务相对于其他线程“特殊”。谢谢你,阿农


如果有人能解释原因,我将不胜感激。

不要使用
任务。运行
获取线程池线程,然后
等待
阻止它。@I3arnon,不确定,你的意思是什么。我需要等待那些
任务
,然后工人才能继续下一个任务=方法。这一切都很好。你根本不需要这些任务,因为你浪费了一个线程等待它们完成。只要让线程执行任务内部的工作。@I3arnon,我知道你的意思,但我需要它们。现在检查更具体的代码。我的评论仍然有效。如果您有
async
功能,那么也可以使用
DoXTask
方法
async
,并使用
SemphoreSlim
而不是
互斥体。
class Program
{
    public class CommonWork
    {
        private Mutex _mutex;
        public CommonWork() { this._mutex = new Mutex(false); }    
        private void Lock() { this._mutex.WaitOne(); }    
        private void Unlock() { this._mutex.ReleaseMutex(); }

        public void DoFirstTask(int taskId)
        {
            this.Lock();
            try
            {
                // imitating sync work from 3rd Party lib, that I need to make async
                var t = Task.Run(() => { 
                    Thread.Sleep(500); // sync work
                });
                ... // doing some work here
                t.Wait();
                Console.WriteLine("Task {0}: DoFirstTask - complete", taskId);    
            }
            finally { this.Unlock(); }
        }

        public void DoSecondTask(int taskId)
        {
            this.Lock();
            try
            {
                // imitating sync work from 3rd Party lib, that I need to make async
                var t = Task.Run(() => { 
                    Thread.Sleep(500); // sync work
                });
                ... // doing some work here
                t.Wait();
                Console.WriteLine("Task {0}: DoSecondTask - complete", taskId);
            }
            finally { this.Unlock(); }
        }

        public void DoThirdTask(int taskId)
        {
            this.Lock();
            try
            {
                // imitating sync work from 3rd Party lib, that I need to make async
                var t = Task.Run(() => { 
                    Thread.Sleep(500); // sync work
                });
                ... // doing some work here
                t.Wait();
                Console.WriteLine("Task {0}: DoThirdTask - complete", taskId);
            }
            finally { this.Unlock(); }
        }
    }

    // Worker class

    public class Worker
    {
        private  CommonWork CommonWork { get; set; }
        public Worker(CommonWork commonWork)
        { this.CommonWork = commonWork; }

        private void Loop()
        {
            while (true)
            {
                this.CommonWork.DoFirstTask(Task.CurrentId.Value);
                if (Task.CurrentId.Value < 3)
                {
                    this.CommonWork.DoSecondTask(Task.CurrentId.Value);
                    this.CommonWork.DoThirdTask(Task.CurrentId.Value);
                }
            }
        }

        public Task Start()
        {
            return Task.Run(() => this.Loop());
        }
    }

    static void Main(string[] args)
    {
        var work = new CommonWork();
        var client1 = new Worker(work);
        var client2 = new Worker(work);
        var client3 = new Worker(work);
        client1.Start();
        client2.Start();
        client3.Start();
        Console.ReadKey();
    }
} // end of Program