zoukankan      html  css  js  c++  java
  • 多线程同步技术(一)

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

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

    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每次只被一个线程占用,只有释放之后,另外的线程才可以进入;

  • 相关阅读:
    八、比卦
    七、师卦
    六、讼卦
    五、需卦
    力扣-两数之和
    什么是3NF (范式) ?
    SQL事务4个特性
    什么是索引?
    假设把只包含01的数组(如{0,0,1,1,1,0,1,0,0,1})按照升序排序,可以任意交换两个数的位置,请输出最少需要交换的次数。
    找规律并用编程实现如下数列(数值超过10000停止打印) 1,1,2,2,3,2,5,4,8,8
  • 原文地址:https://www.cnblogs.com/yeshuimaowei/p/7458772.html
Copyright © 2011-2022 走看看