C Sharp/多线程与同步
外观
< C Sharp
C#提供了至少六种多线程并发的实现:
- 线程类:
var t = new Thread(BackgroundTask);t.Start("Thread");
- 异步委托:
Action<string> d = BackgroundTask; d.BeginInvoke("BeginInvoke", null, null);
- 线程池:
ThreadPool.QueueUserWorkItem(BackgroundTask, "ThreadPool");
- BackgroundWorker类:
BackgroundWorker _demoBGWorker = new BackgroundWorker(); _demoBGWorker.DoWork += myWorkHorse;_demoBGWorker.RunWorkerAsync();
- Task Parallel Library (TPL):
Task.Run(() => BackgroundTask("TPL"));
- async await
Thread
类
[编辑]System.Threading.Thread
类提供了基本功能。创建Thread
类实例,参数为ThreadStart
或ParameterizedThreadStart
指向委托函数。如下例:
using System;
using System.Threading;
public static class Program
{
private static void SecondThreadFunction()
{
while (true)
{
Console.WriteLine("Second thread says hello.");
Thread.Sleep(1000); // pause execution of the current thread for 1 second (1000 ms)
}
}
public static void Main()
{
Thread newThread = new Thread(new ThreadStart(SecondThreadFunction));
newThread.Start();
while (true)
{
Console.WriteLine("First thread says hello.");
Thread.Sleep(500); // pause execution of the current thread for half a second (500 ms)
}
}
}
void ParameterizedThreadStart(object obj)
委托允许给新线程传递一个参数:
using System;
using System.Threading;
public static class Program
{
private static void SecondThreadFunction(object param)
{
while (true)
{
Console.WriteLine("Second thread says " + param.ToString() + ".");
Thread.Sleep(500); // pause execution of the current thread for half a second (500 ms)
}
}
public static void Main()
{
Thread newThread = new Thread(new ParameterizedThreadStart(SecondThreadFunction));
newThread.Start(1234); // here you pass a parameter to the new thread
while (true)
{
Console.WriteLine("First thread says hello.");
Thread.Sleep(1000); // pause execution of the current thread for a second (1000 ms)
}
}
}
也可写成:
using System;
using System.Threading;
Thread t2 = new Thread(() => { MyWorkHorseFunc(MyParam1); });
t2.Start();
共享数据
[编辑]下例2个线程访问同一个变量,并不安全:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
int number = 1;
Thread newThread = new Thread(new ThreadStart(delegate
{
while (true)
{
number++;
Console.WriteLine("Second thread says " + number.ToString() + ".");
Thread.Sleep(1000);
}
}));
newThread.Start();
while (true)
{
number++;
Console.WriteLine("First thread says " + number.ToString() + ".");
Thread.Sleep(1000);
}
}
}
异步委托
[编辑]using System;
public static class Program
{
delegate int del(int[] data);
public static int SumOfNumbers(int[] data)
{
int sum = 0;
foreach (int number in data) {
sum += number;
}
return sum;
}
public static void Main()
{
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
del func = SumOfNumbers;
IAsyncResult result = func.BeginInvoke(numbers, null, null);//异步调用,不阻塞
// I can do stuff here while numbers is being added
int sum = func.EndInvoke(result);//等待异步调用完成
//sum = 15
}
}
同步
[编辑]C#支持lock关键字,并在退出其作用域时解锁:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
int number = 1;
object numberLock = new object();
Thread newThread = new Thread(new ThreadStart(delegate
{
while (true)
{
lock (numberLock)
{
number++;
Console.WriteLine("Second thread says " + number.ToString() + ".");
}
Thread.Sleep(1000);
}
}));
newThread.Start();
while (true)
{
lock (numberLock)
{
number++;
Console.WriteLine("First thread says " + number.ToString() + ".");
}
Thread.Sleep(1000);
}
}
}
Thread
类的Join
方法允许线程会合:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Thread newThread = new Thread(new ThreadStart(delegate
{
Console.WriteLine("Second thread reporting.");
Thread.Sleep(5000);
Console.WriteLine("Second thread done sleeping.");
}));
newThread.Start();
Console.WriteLine("Just started second thread.");
newThread.Join(1000);
Console.WriteLine("First thread waited for 1 second.");
newThread.Join();
Console.WriteLine("First thread finished waiting for second thread. Press any key.");
Console.ReadKey();
}
}
任务并行库
[编辑].NET 4引入了 Task Parallel Library (TPL)是当时最好的创建后台任务的方式。有强大的模型,支持链式任务、并行执行、等待一个或多个任务完成,传递cancellation token,甚至控制后台线程。
async和await
[编辑]C# 5和.NET 4.5引入了async和await。这允许你按照同步的方式写源代码但异步执行。可以await任何返回task的方法,对普通方法也可以用TPL包装后await:
await Task.Run(() => xdoc.Load("http://feeds.feedburner.com/soundcode"));
一个特别好处是在UI线程中await一个方法时,会返回UI线程恢复执行:
await Task.Run(() => xdoc.Load("http://feeds.feedburner.com/soundcode"));
label1.Text = "Done"; // we’re back on the UI thread!
还可以使用try和catch包住异步线程:
private async void OnButtonAsyncAwaitClick(object sender, EventArgs e)
{
const string state = "Async Await";
this.Cursor = Cursors.WaitCursor;
try
{
label1.Text = String.Format("{0} Started", state);
await AwaitableBackgroundTask(state);
label1.Text = String.Format("About to load XML");
var xdoc = new XmlDocument();
await Task.Run(() => xdoc.Load("http://feeds.feedburner.com/soundcode"));
label1.Text = String.Format("{0} Done {1}", state, xdoc.FirstChild.Name);
}
catch (Exception ex)
{
label1.Text = ex.Message;
}
finally
{
this.Cursor = Cursors.Default;
}
}