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();
                
            }

    运行结果:

  • 相关阅读:
    理解WebKit和Chromium: Web应用和Web运行环境
    理解WebKit和Chromium: 网页渲染的基本过程
    【闲谈】我的大学
    使用GDAL将下载的Google卫星图像转为带坐标的tif
    Linux下使用GDAL进行开发(automake使用)
    Linux下编译GDAL
    【Unity技巧】统一管理回调函数——观察者模式
    【Unity技巧】使用单例模式Singleton
    【Unity插件】LitJson杂谈
    理解WebKit和Chromium:Chromium资源磁盘缓存
  • 原文地址:https://www.cnblogs.com/qiuguochao/p/7413870.html
Copyright © 2011-2022 走看看