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个信号量已经满了,线程继续等待

    }

    }

     

  • 相关阅读:
    一些业内有名的网站收集
    WCF重载
    FCKEditor fckconfig.js配置,添加字体和大小 附:中文字体乱码问题解决
    查询第几条到第几条的数据的SQL语句
    SPOJ 9939 Eliminate the Conflict
    UVA 10534 Wavio Sequence
    HDU 3474 Necklace
    POJ 2823 Sliding Window
    UVA 437 The Tower of Babylon
    UVA 825 Walking on the Safe Side
  • 原文地址:https://www.cnblogs.com/yinhaichao/p/3229302.html
Copyright © 2011-2022 走看看