zoukankan      html  css  js  c++  java
  • 【C#多线程编程实战笔记】二、 线程同步

    使用Mutex类-互斥锁

    owned为true,互斥锁的初始状态就是被主线程所获取,否则处于未获取状态

    name为定义的互斥锁名称,在整个操作系统只有一个命名未CSharpThreadingCookbook的互斥量,一个线程得到,其他线程就无法得到这个互斥量了,只能等待。

    const string mutexName = "CSharpThreadingCookbook";
    public Mutex(bool initiallyOwned, string mutexName);
    public Mutex();

    WaitOne():获取,mut.ReleaseMutex():释放

    public override bool WaitOne()
    public static Mutex mutex = new Mutex();

    //
    获取互斥锁,已经被其他线程获取,挂起等待。 mut.WaitOne(); //代码 //... //... //释放锁 mut.ReleaseMutex();

     SemaphoreSlim类,限制同一资源被同时访问的线程数量

     有10个线程同时去访问数据库,借助信号类限制访问数据的并发线程数量,当有4个线程同时正在访问资源,其他线程必须等待,直至有资源执行完被释放。

    class Program
        {
            static SemaphoreSlim _seamp = new SemaphoreSlim(4);
            static void Main(string[] args)
            {
                for (int i = 1; i <=10; i++)
                {
                    int j = i;
                    int sencondsToWait = 2 + 2 * i;
                    var t = new Thread(()=> { method(j.ToString(),sencondsToWait); });
                    t.Start();
                }
                Console.ReadLine();
            }
            static void method(string name,int senconds)
            {
                Console.WriteLine($"{name} waits to access a database");
                _seamp.Wait();
                Console.WriteLine($"{name} is completed");
                Thread.Sleep(TimeSpan.FromSeconds(senconds));
                _seamp.Release();
            }
        }

     ManualResetEvent:线程间相互通信,一个线程开始一个活动,结束后告诉另一个线程可以进行执行了。

    通过构造函数来控制 ManualResetEvent 的初始状态。

    1.当初始值未false时,为非终止状态;_mre.WaitOne()阻塞线程,不允许线程访问下边的语句

    static ManualResetEvent _mre = new ManualResetEvent(false);

    2.当初始值未true时,为终止状态;_mre.WaitOne()允许线程访问下边的语句

    static ManualResetEvent _mre = new ManualResetEvent(true);

    在非终止状态时怎么让线程继续执行,怎么再让它停下来,这就要用了set()和Reset()方法了

    • 把非终止状态改为终止状态用Set()方法,告诉线程活动可以继续执行了(打开大门)
    • 把终止状态改为非终止状态用Reset()方法,阻塞线程直到再调用 Set()方法(关闭大门直至打开)

    场景:

    一个线程进行一个活动后,调用WaitOne()阻塞线程,等待其他线程给我信号我再继续执行。

    另一个线程执行Set(),告诉正在等我执行完的线程,你可以执行了。随后Reset(),没有来得及执行的线程只能继续等待,直至再次接收信号。

    CountDownEvent:信号类,等待直到一定数量的操作完成。

    创建一个CountDownEvent实例,在构造函数中指定了当两个操作完成时会发出信号

    static CountDownEvent _countDown = new CountDownEvent(2);
    static void method()
    {
          Console.WriteLine("111111");
          _countDown.Signal();
    }
    
    var t1=new thread(()=>method());
    t1.Start();
    _countDown.Wait();
    _countDown.dispose();
    如果_countDown.Signal()没有达到指定的次数,那么_countDown.Wait()会一直等待,所以上面代码将会一值等待。

    Barrier:像一个屏障,把所有线程任务的阶段隔离开来,当前阶段所有线程不完成,不会开始下一个阶段。

    当屏障接收到所有的参与者,participantCount: 参与线程的数量,完成某个阶段的信号后,就会执行“阶段后代码”,

    然后barrier.CurrentPhaseNumber会递增其值,表示要运行新的阶段,然后再解除阻塞每一个参与者的Task实例,然后所有参与者开始下一个阶段。

    让【多个任务】在【不同阶段】同步一次(碰面),在继续往后执行。

            //同步两个线程,以及指定回调函数
            static Barrier _barrier = new Barrier(2, b =>  Console.WriteLine($"{b.CurrentPhaseNumber+1}当前阶段线程都执行完了,碰面一次") );
            static void Main(string[] args)
            {
                
                var t1 = new Thread(() => Method_1());
                var t2 = new Thread(() => Method_2());
                t1.Start();
                t2.Start();
                Console.ReadLine();
            }
    
            /// <summary>
            /// 线程1要执行的方法
            /// </summary>
            public static  void Method_1()
            {
                //模拟阶段一
                Thread.Sleep(TimeSpan.FromSeconds(5));
                Console.WriteLine("【阶段一】,线程【1】执行完毕");
                _barrier.SignalAndWait(); 
    
                //模拟阶段二
                Thread.Sleep(TimeSpan.FromSeconds(5));
                Console.WriteLine("【阶段二】,线程【1】执行完毕");
                _barrier.SignalAndWait();
            }
    
            /// <summary>
            /// 线程2要执行的方法
            /// </summary>
            public static void Method_2()
            {
                //模拟阶段一
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("【阶段一】,线程【2】执行完毕");
                _barrier.SignalAndWait();
    
                //模拟阶段二
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("【阶段二】,线程【2】执行完毕");
                _barrier.SignalAndWait();
                
            }

    运行结果:

  • 相关阅读:
    克如斯卡尔 P1546
    真正的spfa
    第四课 最小生成树 要点
    关于vscode中nullptr未定义
    cmake学习笔记
    python学习笔记
    (BFS 图的遍历) 2906. kotori和迷宫
    (图论基础题) leetcode 997. Find the Town Judge
    (BFS DFS 并查集) leetcode 547. Friend Circles
    (BFS DFS 图的遍历) leetcode 841. Keys and Rooms
  • 原文地址:https://www.cnblogs.com/qiuguochao/p/7413870.html
Copyright © 2011-2022 走看看