深入理解.Net中的线程同步之构造模式(二)内核模式构造Semaphone

108 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

深入理解.Net中的线程同步之构造模式(二)内核模式构造Semaphone

@TOC

前言

Kernel-mode Constructs一般翻译为内核模式构造 , Constructs 即是一个名词也是一个动词,但是翻译为构造感觉有点像一个动词,个人感觉翻译为名词更好,毕竟是加了s的,就表示多个,动词显然不能表示多个啊,比如内核模式构造物,内核模式构造体。


环境说明 IDE:Visual Studio 2022
OS:Win10
.NET:.Net4.6.1

一、信号量是什么?

信号量是什么?记得嵌入式的时候老师说过通过0,1来控制线程的阻断和解除阻断就是信号量。这个就是信号量最基础的理解了,信号量其实是由系统内核控制的具有原子性的int变量,为0时阻塞线程,大于0时解除阻塞。

二、代码编写

1.编写一个Semaphone的锁

代码如下(示例):

       public sealed class SemaphoreLock : IDisposable
    {
        private Semaphore  m_available;
        public SemaphoreLock(int maxConcurrent)
        {
            m_available = new Semaphore(maxConcurrent, maxConcurrent); // 
        }

        public void Enter()
        {
            // Block in kernel until resource available
            m_available.WaitOne();
        }

        public void Leave()
        {
            // Let another thread access the resource
            m_available.Release(1);
        }

        public void Dispose() 
        {
            m_available.Dispose(); 
        }
    }

2.测试Semaphone锁的效果

代码如下(示例):

  public class SemaphoreTest
    {

        public void TestStart() 
        {
        
            Console.WriteLine(" SemaphoreTest TestStart Start !");
            IntObj intObj = new IntObj();
      
            for (Int32 i = 0; i < 10; i++)
            {
            
                new TaskFactory().StartNew(() =>
                {
                    AddCount(intObj);
                    AddCount_SemaphoreLock(intObj);
                });
            }
            Console.WriteLine(" SemaphoreTest TestStart END !");
        }
        
        public void AddCount(IntObj intObj)
        {  

            intObj.num_Norml++;
            WriteLineThread(intObj);
            Thread.Sleep(500);
        }
        SemaphoreLock tLock = new SemaphoreLock(1);

        public void AddCount_SemaphoreLock(IntObj intObj)
        {
            tLock.Enter();

            intObj.num_Lock++;
            WriteLineThread_SemaphoreLock(intObj);
            Thread.Sleep(500);
            tLock.Leave();
            tLock.Leave();
        }
        public void WriteLineThread(IntObj intObj )
        {
            Thread.Sleep(200);
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine($"num_Norml :{ intObj.num_Norml},{Thread.CurrentThread.ManagedThreadId}");
            Console.ForegroundColor = currentForeColor;
            Thread.Sleep(200);
        }

        public void WriteLineThread_SemaphoreLock(IntObj intObj)
        {
            Thread.Sleep(200);
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"num_Lock:{ intObj.num_Lock},{Thread.CurrentThread.ManagedThreadId}");
            Console.ForegroundColor = currentForeColor;
            Thread.Sleep(200);
        }

    }

效果如下

当信号量锁初始化的时候允许最大10个线程效果
image.png
当信号量锁初始化的时候允许最大1个线程效果

image.png
此时的结果就和AutoResetEvent事件锁一样的效果了


总结

可以看出,当最大线程数1的时候,信号量和AutoResetEvent事件效果一样。 当最大线程数大于1的时候,将可能有多个线程同时变量。这种多个线程访问一个资源的情况一般用于读写锁的读时