多线程同步技术(一)

多线程编程过程中,难免会涉及到资源共享的问题,在并发的线程中,如果不对线程加以控制,线程抢夺共享资源,对资源的读取和修改混乱,结果会导致不是我们想要的结果,这就需要引入线程同步的技术。

先演示下没有同步技术的案例:

class ThreadTT
    {
        int counter = 0;
        public void LockTest()
        {
            Thread t1 = new Thread(new ParameterizedThreadStart(Run));
            Thread t2 = new Thread(new ParameterizedThreadStart(Run));
            Thread t3 = new Thread(new ParameterizedThreadStart(Run));

            t1.Start("t1");
            t2.Start("t2");
            t3.Start("t3");
        }
        public void Run(object id)
        {
                for (int i = 0; i < 100; i++)
                {
                    counter++;
                    Thread.Sleep(100);
                    counter--;
                    Console.WriteLine("{0} counter {1}", id, counter);
                }
        }
    }

当执行LockTest() 方法之后,打印出的counter的值则是错乱的:

image

下面开始引入同步技术:

1.LOCK

class ThreadTT
    {
        int counter = 0;
        public void LockTest()
        {
            Thread t1 = new Thread(new ParameterizedThreadStart(Run));
            Thread t2 = new Thread(new ParameterizedThreadStart(Run));
            Thread t3 = new Thread(new ParameterizedThreadStart(Run));

            t1.Start("t1");
            t2.Start("t2");
            t3.Start("t3");
        }
        private  object obj = new object();
        public void Run(object id)
        {
            lock (obj)
            {
                for (int i = 0; i < 100; i++)
                {
                    counter++;
                    Thread.Sleep(100);
                    counter--;
                    Console.WriteLine("{0} counter {1}", id, counter);
                }
            }
        }
    }

再运行LockTest :

image

现在counter每次都只有一个线程占用;

2.Monitor

class ThreadTT
    {
        int counter = 0;
        public void LockTest()
        {
            Thread t1 = new Thread(new ParameterizedThreadStart(Run));
            Thread t2 = new Thread(new ParameterizedThreadStart(Run));
            Thread t3 = new Thread(new ParameterizedThreadStart(Run));

            t1.Start("t1");
            t2.Start("t2");
            t3.Start("t3");
        }
        private static  object obj = new object();
        public void Run(object id)
        {
            Monitor.Enter(obj);
                for (int i = 0; i < 10; i++)
                {
                    counter++;
                    Thread.Sleep(100);
                    counter--;
                    
                    Console.WriteLine("{0} counter {1}", id, counter);
                }
           Monitor.Exit(obj);
        }
    }

Monitor.Wait() 释放线程锁,并阻塞线程,直到重新获取锁,否则之后的代码不再执行;

Monitor .pulse() 通知正在准备的线程,可以获取线程锁;

static void Main()
        {
            object obj = new object();
            Thread t1 = new Thread(()=> {
                Monitor.Enter(obj);
                Console.WriteLine("t1 enter");
                Console.WriteLine("t1.dosomething");

                Monitor.Wait(obj);
                Thread.Sleep(2000);
                Console.WriteLine("t1 重新获取锁obj");
                Monitor.Pulse(obj);
                Monitor.Exit(obj);
                Console.WriteLine("t1 exit");
            });

            Thread t2 = new Thread(()=> {
                Monitor.Enter(obj);
                
                Console.WriteLine("t2 enter");
                Monitor.Pulse(obj);
                Console.WriteLine("t2 puslse");

                Monitor.Wait(obj);
                Console.WriteLine("t2 重新获取obj");
                Monitor.Exit(obj);
                Console.WriteLine("t2 exit");
            });

            t1.Start();
            t2.Start();

            Console.Read();
        }

image

程序执行,首先进入t1,执行到Monitor.Wait(obj); 线程t1释放锁,并阻塞,开始进入线程t2,执行到Monitor.Wait(obj),线程t2阻塞,线程t1重新获取锁  执行到结束,并释放信号,t2接收到信号,继续执行结束

Monitor.Wait(obj,3000);

当前线程阻塞,等待3s钟,如果没有获取到锁,则继续执行下去

3.Mutex互斥锁

Mutex对象是一个同步基元,可以用来做线程间的同步。

若多个线程需要共享一个资源,可以在这些线程中使用Mutex同步基元。当某一个线程占用Mutex对象时,其他也需要占用Mutex的线程将处于挂起状态,Mutex 通常处于空闲状态,线程在使用的时候通过waitone()来获取一个可用的互斥,如果有,则获取互斥权限,执行线程,如果没有,则阻塞在那里直到等到信号;

private static Mutex mut = new Mutex();
        private const int numIterations = 1;
        private const int numThreads = 3;
        static void Main()
        {
            for (int i = 0; i < numThreads; i++)
            {
                Thread newThread = new Thread(new ThreadStart(ThreadProc));
                newThread.Name = String.Format("Thread{0}", i + 1);
                newThread.Start();
            }

            Console.Read();
        }

        private static void ThreadProc()
        {
            for (int i = 0; i < numIterations; i++)
            {
                UseResource();
            }
        }

        // This method represents a resource that must be synchronized
        // so that only one thread at a time can enter.
        private static void UseResource()
        {
            // Wait until it is safe to enter.
            Console.WriteLine("{0} is requesting the mutex",
                              Thread.CurrentThread.Name);
            mut.WaitOne();

            Console.WriteLine("{0} has entered the protected area",
                              Thread.CurrentThread.Name);

            // Place code to access non-reentrant resources here.

            // Simulate some work.
            Thread.Sleep(500);

            Console.WriteLine("{0} is leaving the protected area",
                Thread.CurrentThread.Name);

            // Release the Mutex.
           mut.ReleaseMutex();
            Console.WriteLine("{0} has released the mutex",
                Thread.CurrentThread.Name);
        }

image

这里可以很清楚的看到,mutex每次只被一个线程占用,只有释放之后,另外的线程才可以进入;

原文地址:https://www.cnblogs.com/yeshuimaowei/p/7458772.html