名称空间:System.Threading
异步委托
异步委托使用线程池。基于IAsyncResult的异步模式。
static int TakesAWhile(int data, int ms)
{
}
public delegate int TakesAWhileDelegate(int data, int ms);
static void Main()
TakesAWhileDelegate dl = TakesAWhile;
IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);
// (1)投票
while (!ar.IsCompleted)
{
// doing something else in the main thread
Thread.Sleep(50);
}
// (2) 等待句柄
while (!ar.AsyncWaitHandle.WaitOne(50, false)) // 超时返回false
{
// doing something else in the main thread
}
int result = dl.EndInvoke(ar); // EndInvoke()方法会一直等待,直到委托完成其任务位置。
// (3) 异步回调
// (3-1) 回调函数
dl.BeginInvoke(1, 3000, TakesAWhileCompleted, dl); // 最后一个参数可以使用ar.AsyncState读取
// (3-2) Lambda表达式
dl.BeginInvoke(1, 3000,
ar =>
{
int result = dl.EndInvoke(ar); // Lambda表达式可以直接访问该作用域外部的变量dl
}
}
// 回调方法在委托线程中调用
static void TakesAWhileCompleted(IAsyncResult ar)
{
if (ar == null) throw new ArgumentNullException("ar");
TakesAWhileDelegate dl = ar.AsyncState as TakesAWhileDelegate;
Trace.Assert(dl != null, "Invalid object type");
int result = dl.EndInvode(ar); // 获得结果
}
Thread
static void Main()
{
// (1) 委托参数为ThreadStart
var t1 = new Thread(ThreadMain);
t1.Start();
// (2) 委托参数为ParameterizedThreadStart
var d = new Data { Message = "Info" };
var t2 = new Thread(ThreadMainWithParameters);
t2.Start(d);
}
static void ThreadMain()
{
}
public struct Data
{
public string Message;
}
static void ThreadMainWithParameters(Object o)
{
Data d = (Data)o;
}
在默认情况下,用Thread类创建的是前台线程,线程池中的线程总是后台线程。Thread类创建时,可以设置IsBackground属性。
只要有一个前台线程在运行,应用程序的进程就在运行。
线程池
static void Main()
{
ThreadPool.QueueUserWorkItem(JobForAThread); // 入池的线程只用于时间较短的任务,如果要一直运行,应使用Thread类创建一个线程
}
static void JobForAThread(Object state)
{
}
任务
任务后台使用ThreadPool。
(1)启动任务
static void TaskMethod()
{
}
static void Main()
{
// using task factory
TaskFactory tf = new TaskFactory();
Task t1 = tf.StartNew(TaskMethod);
// using task factory via a task
Task t2 = Task.Factory.StartNew(TaskMethod);
// using Task constructor
Task t3 = new Task(TaskMethod);
t3.Start();
}
(2)连续的任务
static void DoOnFirst()
{
}
static void DoOnSecond()
{
}
static void Main()
{
Task t1 = new Task(DoOnFirst);
Task t2 = t1.ContinueWith(DoOnSecond);
Task t3 = t2.ContinueWith(DoOnError, TaskConinuationOptions.OnlyOnFaulted);
}
(3)任务的层次结构(父任务启动子任务,取消父任务也会取消子任务)
(4)任务的结果
(4-1)任务结束时,它可以把一些有用的状态写到共享对象,这个共享对象必须是线程安全的。
(4-2)使用Task类的泛型版本,定义返回某个结果的任务。
static Tuple<int, int> TaskWithResult(Object division)
{
}
static void Main()
{
var t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
t1.Start();
t1.Wait(); // wait the task to complete execution
Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
}
Parallel类
定义了并行的for和foreach的静态方法Parallel.For()和Parallel.ForEach(),多次调用同一方法,迭代顺序没有定义。
// For方法的前两个参数定义了循环的开头和结束,第三个参数是一个Action<int>委托,整数参数代表循环的迭代次数
ParallelLoopResult result = Parallel.For(0, 10, i =>
{
});
ParallelLoopResult result = Parallel.For(0, 10, (int i, ParallelLoopState pls) =>
{
if (i > 15) pls.Break();
});
// Parallel.ForEach()方法遍历实现了IEnumerable集合
string[] data = {"one", "two", "three"};
ParallelLoopResult result = Parallel.ForEach<string> (data, s =>
{
});
ParallelLoopResult result = Parallel.ForEach<string> (data, (s, pls, l) =>
{
});
Parallel.Invoke()调用多个方法并行运行
同步
争用条件:如果多个线程访问相同对象,或访问不同步的共享状态,就会出现争用条件。用lock解决:(1)锁定共享的对象,这可以在线程中完成;(2)将共享对象设置为线程安全的对象。
死锁:至少有两个线程被挂起,并等待对方解除锁定。避免死锁的方法:(1)从一开始就设计好锁定顺序;(2)为锁定定义超时时间。
同步技术:进程内:lock语句,Interlocked类,Monitor类;进程间:Mutex类,Semaphore类,Event类,ReaderWriterLockSlim类。
(1)lock语句
(1-1)对象锁:只有引用类型才能用于锁定。
(1-2)要锁定静态成员,把锁放在object类型上:
lock (typeof(StaticClass))
{
}
(1-3)用lock关键字可以将类的实例成员函数设置为线程安全的。
public class Demo
{
private static readonly Object syncRoot = new Object();
public void DoThis()
{
lock(this.syncRoot)
{
// only one thread at a time can access DoThis
}
}
}
reference:
http://blog.csdn.net/maths_bai/article/details/5999970
(1-4)可以创建类的两个版本,一个同步版本,一个异步版本。
public class Demo
{
private class SynchronizedDemo : Demo
{
public int State { get; set; }
private Object syncRoot = new Object();
private Demo d;
public SynchronizedDemo(Demo d)
{
this.d = d;
}
public override bool IsSynchronized
{
get { return true; }
}
public override void DoThis()
{
lock (this.syncRoot)
{
d.DoThis();
}
}
}
public virtual bool IsSynchronized
{
get { return false; }
}
public static Demo Synchronized(Demo d)
{
if (!d.IsSynchronized)
{
return new SynchronizedDemo(d);
}
return d;
}
public virtual void DoThis()
{
}
}
在一个地方使用lock语句并不意味着,访问对象的其他线程都正在等待。必须对每个访问共享状态的线程显式地使用同步功能。
(2)Interlocked类
用于使变量的简单语句原子化,提供了以线程安全的方式递增、递减、交换和读取值的方法。
Interlocked.CompareExchange<SomeState>(ref someState, newState, null);
Interlocked.Increment(ref state);
(3)Monitor类
Monitor.Enter(obj);
try
{
// synchronized region for obj
}
finally
{
Monitor.Exit(obj);
}
与lock语句相比,Monitor类的主要优点是:可以添加一个等待被锁定的超时值。
bool lockTaken = false;
Monitor.TryEnter(obj, 500, ref lockTaken);
if (lockTaken)
{
try
{
// acquired the lock
// synchronized region for obj
}
finally
{
Monitor.Exit(obj);
}
}
else{
// do something else
}
(4)WaitHandle抽象基类
用于等待一个信号的设置,可设置最长等待时间。
WaitOne()
static WaitAll()
static WaitAny()
Mutex, EventWaitHandle, Semaphore都派生自WaitHandle基类。
(5)Mutex类
互斥名字用于进程间共享
bool createdNew;
Mutex mutex = new Mutex(false, "ProMutex", out createdNew);
打开已有互斥Mutex.OpenExisting()
if (mutex.WaitOne()) // 获得互斥锁定,在该过程中成为该互斥的拥有者
{
try
{
// synchronized region
}
finally
{
mutex.ReleaseMutex();
}
}
else
{
// some problem happened while waiting
}
由于系统能识别有名称的互斥,因此可以使用它禁止应用程序启动两次。
static void Main()
{
bool createdNew;
Mutex mutex = new Mutex(false, "SingletonMutex", createdNew);
if (!createdNew)
{
Application.Exit();
return;
}
}
(6)Monitor和Mutex,只有一个线程能拥有锁定;Semaphore可以由多个线程使用,是一种记数的互斥锁定,可以定义允许同时访问受旗语锁定保护的资源的线程个数。。
Semaphore类和SemaphoreSlim类。
static void Main()
{
int threadCount = 6;
int semaphoreCount = 4;
var semaphore = new SemaphoreSlim(semaphoreCount, semaphoreCount);
for (int i =0; i<threadCount; i++)
{
thread[i] = new Thread(ThreadMain);
thred[i].Start(semaphore);
}
for (int i =0; i<threadCount; i++)
{
thread[i].Join();
}
}
static void ThreadMain(object o)
{
SemaphoreSlim semaphore = o as SemaphoreSlim;
bool isCompleted = false;
while (!isCompleted)
{
if (semaphore.Wait(600)
{
try
{
// do synchronized job
}
finally
{
semaphore.Release();
isCompleted = true;
}
}
else
{
// timeout, wait again
}
}
}
(7)Events类
ManualResetEvent, AutoResetEvent, ManualResetEventSlim, CountdownEvent类,从托管代码中使用系统事件。事件可以发信号Set(),也可以不发信号Reset(),使用WaitHandle类,任务可以等待出于发信号状态的事件。
public class Calculator
{
private ManualResetEventSlim mEvent;
public int Result { get; private set; }
public Calculator(ManualResetEventSlim ev)
{
this.mEvent = ev;
}
public void Calculation(object obj)
{
Tuple<int, int> data = (Tuple<int, int>)obj;
Thread.Sleep(new Random().Next(3000));
Result = data.Item1 + data.Item2;
mEvent.Set();
}
}
static void Main()
{
const int taskCount = 4;
var mEvents = new ManualResetEventSlim[taskCount];
var waitHandles = new WaitHandle[taskCount];
var calcs = new Calculator[taskCount];
TaskFactory taskFactory = new TaskFactory();
for (int i=0; i<taskCount; i++)
{
mEvents[i] = new ManualResetEventSlim(false);
waitHandles[i] = mEvents[i].WaitHandle;
calcs[i] = new Calculator(mEvents[i]);
taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i+1, i+3));
}
for (int i=0; i<taskCount; i++)
{
int index = WaitHandle.WaitAny(mEvents);
if (index == WaitHandle.WaitTimeout)
{
// timeout
}
else
{
mEvents[index].Reset();
// get Result;
}
}
}
为了把一些工作分支到多个任务中,并在以后合并结果,使用CountdownEvent类,只需创建一个事件对象。
public class Calculator
{
private CountdownEvent mEvent;
public int Result { get; private set; }
public Calculator(CountdownEvent ev)
{
this.mEvent = ev;
}
public void Calculation(object obj)
{
Tuple<int, int> data = (Tuple<int, int>)obj;
Thread.Sleep(new Random().Next(3000));
Result = data.Item1 + data.Item2;
mEvent.Signal();
}
}
static void Main()
{
const int taskCount = 4;
var cEvent = new CountdownEvent(taskCount);
var calcs = new Calculator[taskCount];
TaskFactory taskFactory = new TaskFactory();
for (int i=0; i<taskCount; i++)
{
calcs[i] = new Calculator(mEvents[i]);
taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i+1, i+3));
}
cEvent.Wait(); // Wait for all finished.
for (int i=0; i<taskCount; i++)
{
// get Result;
}
}
Timer
(1)System.Threading.Timer在构造函数中传递一个委托。
private static void ThreadingTimer()
{
var t1 = new System.Threading.Timer(TimeAction, null, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3));
Thread.Sleep(15000);
t1.Dispose();
}
static void TimeAction(object o)
{
Console.WriteLine("time: {0:T}", DateTime.Now);
}
(2)System.Timers.Timer组件,派生自Component基类,基于事件机制。
private static void TimersTimer()
{
var t1 = new System.Timers.Timer(1000);
t1.AutoReset = true;
t1.Elapsed += TimeAction;
t1.Start();
Thread.Sleep(15000);
t1.Stop();
t1.Dispose();
}
static void TimeAction(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("time: {0:T}", e.SignalTime);
}