多线程的实现
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))
}
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、Monitor(lock被编译器解析为Monitor)、Mutex、Semaphore
比如:对于同一个对象,我遍历出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被编译器解析为Monitor,Monitor调用Enter(object )方法,让线程一直等待,直到当前线程被对象锁定,才开始操作,当然不管是运行结束还是触发异常,我们都必须调用Exit(object )方法,当然Monitor优于lock的地方在于他可以设置等待锁定时间,即TryEnter方法
例如,设置让线程等待500毫秒,如果发现还被其他线程锁定,就返回lockif为false,
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个信号量已经满了,线程继续等待
}
}