线程,委托和同步的技术理顺

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

}

}

 

 

 

 

 

posted @ 2013-08-01 09:23  蹦极的馒头  阅读(599)  评论(0编辑  收藏  举报