zoukankan      html  css  js  c++  java
  • 线程,委托和同步的技术理顺

    多线程的实现
    1、多线程的实现方式
           (一):异步委托(本质是微软会创建一个执行任务的线程,是使用线程池来完成异步任务),实现异步委托的技术大概有三种,投票、等待句柄、异步回调。
           1、投票:
                  public delegate int TakesAWhileDelege(int ms);

            static void Main(string[] args)

            {

                TakesAWhileDelege dl=TakesAWhile;

                IAsyncResult ar = dl.BeginInvoke(1000,null,null);

                while (ar.IsCompleted)

                    Console.WriteLine("委托执行完成");

            }

            public static int TakesAWhile(int ms)

            {

                Thread.Sleep(50);

                return ms;

            }

    2、等待句柄(通过AsyncWaitHandle获取委托的等待句柄WaitHandle,通过该句柄的方法WaitOne方法,即阻止当前线程50毫秒,如果超过50毫秒后该委托还没有完成就返回false)
                  public delegate int TakesAWhileDelege(int ms);

            static void Main(string[] args)

            {

                TakesAWhileDelege dl = TakesAWhile;

                IAsyncResult ar = dl.BeginInvoke(1000, null, null);

                while (true)

                {

                    if (ar.AsyncWaitHandle.WaitOne(50, false))

                        break;

                }

                int result = dl.EndInvoke(ar);

            }

            public static int TakesAWhile(int ms)

            {

                Thread.Sleep(50);

                return ms;

            }

    3、异步回调,(t通过BeginInvoke的最后两个参数,一个是回调函数,一个是)
                 

    public delegate int TakesAWhileDelege(int ms);

            static void Main(string[] args)

            {

                TakesAWhileDelege dl = TakesAWhile;

                dl.BeginInvoke(1000, completeTake, dl);

               Console.WriteLine("adfa");

            }

            public static void completeTake(IAsyncResult ar)

            {

               

    //如果 dl.BeginInvoke(1000, completeTake, dl);中的dl是任何一个参数比如2000,那么这里获取就是

                //int num = (int)ar.AsyncState;
                TakesAWhileDelege dlTemp = ar.AsyncState as TakesAWhileDelege;

               int result= dlTemp.EndInvoke(ar);

            }

            public static int TakesAWhile(int ms)

            {

                Thread.Sleep(50);

                return ms;

            }



           (二):用Thread类创建线程(无参和有参,另外传递参数的另一种方法是构建一个类对象,参数作为类对象的成员,然后定义一个threadClass3方法,用于在构造Thread对象的时候传递在如:Thread thread2 = new Thread(threadClass3))
           我先声明,用Thread类声明的线程默认都是前台线程,即及时main函数执行完毕后,只要有一个前台线程没有完毕,都会不会终止进程,除非你把IsBackground 改为true,改完后则主线程结束,后台线程也跟着结束,不论他有没有执行完毕
           1、普通有参和无参
                  static void Main(string[] args)

            {

                Thread thread1 = new Thread(threadClass1) { Name = "11", IsBackground = false };

                thread1.Start();

                Thread thread2 = new Thread(threadClass2) { IsBackground = true };

                thread2.Start(100);

            }

            static void threadClass1()

            {

            }

            static void threadClass2(object num)

            {

                int nums = (int)num;

            }

        2、通过构建类对象
        public class Mythread
        {

    Private int num;
        public void Mythread(int num)
    {

    This.num=num;
    }

    Public void threadClass3()

    {

    //xxxxxxxxxxxxxxxxxxx

    }
    }
    调用线程的时候,
    Mythread my1=new Mythread(100);
    Thread th1=new Thread(my1.threadClass3);

    3、 thread1.Join();
            Join:是值阻塞这个thread1进程,一直等待这个进程完成后,才继续往下执行
        thread1.Abort();
            Abort:是终止线程

    (三):线程池(线程池中的线程必须是后台线程,线程池的进程只能用于时间较短的任务,长时间的线程的话最好新建一个线程)
                  1、没有参数
            static void Main(string[] args)

            {

                for (int i = 0; i <= 5; i++)

                    ThreadPool.QueueUserWorkItem(threadClass);

                Console.ReadLine();

            }

            static void threadClass(object num)

            {

                Thread.Sleep(3000);

                Console.WriteLine(Thread.CurrentThread.ManagedThreadId );

            }
            2、有参数
        构建一个类,参数作为类的成员
          public class MythreadA

        {

          private int num=100;

            public MythreadA(int numS)

          {

              this.num = numS;

          }

          public void threadClass3(object N)

          {

              Thread.Sleep(3000);

              Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + num);

            }

        }
    用线程池

    static void Main(string[] args)

            {

                for (int i = 0; i <= 5; i++)

                {

                    MythreadA Mythread1 = new MythreadA(100+i);

                    //QueueUserWorkItem需要一个WaitCallback委托作为参数,该委托必须要一个object类型参数,如果我们需要传递参数,可以新建一个类。。

                    ThreadPool.QueueUserWorkItem(Mythread1.threadClass3);

                   

                }

                Console.ReadLine();

            }

    2、同步的实现方式
    上面说的都是异步的实现,事实上有时候我们也需要不同线程共享文件或者数据,这就需要保证一次只能一个线程访问和改变共享的状态,所以这就要用到同步技术
    多线程同步技术有:
    lock
    Monitorlock被编译器解析为Monitor)、MutexSemaphore

    比如:对于同一个对象,我遍历出20个进程,都把该对象传递过去,对该对象的成员num做循环5000次加1操作,此时会出现的问题是,当第一个线程的i等于2000,判断<5000可以进入循环体的时候,突然线程给了第二个线程,第二个线程继续执行它上次在i=1的时候暂停的操作,这时i突然变成2000,相当于少加了1999次。。如果经常发生这种情况,最后的20个线程的总的结果必定小于10000

    Lock
    (锁定)
    private object o=new object
    for(int i=0;i<5000;i++)
    {
           lock(object )
           {
                  num++;
           }
    }

    Monitor
    private object o=new object

    lock
    被编译器解析为MonitorMonitor调用Enterobject )方法,让线程一直等待,直到当前线程被对象锁定,才开始操作,当然不管是运行结束还是触发异常,我们都必须调用Exitobject )方法,当然Monitor优于lock的地方在于他可以设置等待锁定时间,即TryEnter方法
    例如,设置让线程等待500毫秒,如果发现还被其他线程锁定,就返回lockiffalse
    bool lockif=false

    Monitor.TryEnter(object,500,ref lockif);
    if(lockif)


           //
    执行操作


    Mutex(
    互斥)互斥继承WaitHandle(WaitHandle在异步委托的时候讲过)
    互斥和Monitor也很类似,也是确保只有一个进程被互斥锁定,区别在于互斥可以跨越

    多个进程(注意不是线程)来互斥同步,比如应用程序是否只能启动一个,当然要达到这种效果必须为互斥命名,不命名的互斥不能跨进程。

    Mutex mymutex = new Mutex(false,"myMutex",out mutexif);

                if (!mutexif)

                {

                    //执行代码

                }

    或者******************************

                if (mymutex.WaitOne(50))

                {

                    //终止线程50毫秒,直到该线程已经操作结束

                    //执行代码

                }

    Semaphore(信号量),也继承WaitHandle
    信号量类似互斥锁定Mutex,它是一种控制线程数量的互斥锁定,首先
    先定义一个信号量
    var semaphore=new SemaphoreSlim(4,4);
    然后遍历20个进程,把semaphore作为参数传到每一个进程执行的方法里
    SemaphoreSlim semaphore=o as SemaphoreSlim ;

    Bool isCompleted=false;

    While(!isCompleted)
    {

    //阻止当前进程,一直到他可以进入semaphore信号量内为止
           if(semaphore..Wait(600))
           {
                  try

    {

    }finally

    {

    semaphore.Release();//释放一个信号量,当然也可以指定释放几个信号量参数

    isCompleted=true;

    }

    }else

    {

    //4个信号量已经满了,线程继续等待

    }

    }

     

  • 相关阅读:
    【BZOJ-3627】路径规划 分层图 + Dijkstra + spfa
    Codeforces 刷水记录
    【POJ-1390】Blocks 区间DP
    【BZOJ-1656】The Grove 树木 BFS + 射线法
    【BZOJ-1127】KUP 悬线法 + 贪心
    【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
    【BZOJ-1570】BlueMary的旅行 分层建图 + 最大流
    【BZOJ-2325】道馆之战 树链剖分 + 线段树
    Codeforces乱刷集合
    【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组
  • 原文地址:https://www.cnblogs.com/yinhaichao/p/3229302.html
Copyright © 2011-2022 走看看