//一个简单的示例
//
HelloWordThread.cs
//
------------------------using System;
using System.Threading;
public class Test
... {
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Console.WriteLine ("Main thread: {0}", i);
Thread.Sleep(1000);
}
}
static void ThreadJob()
...{
for (int i=0; i < 10; i++)
...{
Console.WriteLine ("Other thread: {0}", i);
Thread.Sleep(500);
}
}
} 结果:
Main thread: 0
Other thread: 0
Other thread: 1
Main thread: 1
Other thread: 2
Other thread: 3
Main thread: 2
Other thread: 4
Other thread: 5
Main thread: 3
Other thread: 6
Other thread: 7
Main thread: 4
Other thread: 8
Other thread: 9
// UsingDelegate.cs
------------------------------------
using System;
using System.Threading;
public class Test
... {
static void Main()
...{
Counter foo = new Counter();
ThreadStart job = new ThreadStart(foo.Count);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Console.WriteLine ("Main thread: {0}", i);
Thread.Sleep(1000);
}
}
}
public class Counter
... {
public void Count()
...{
for (int i=0; i < 10; i++) ...{ Console.WriteLine ("Other thread: {0}", i);
Thread.Sleep(500);
}
}
}
using System.Threading;
public class Test
... {
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Console.WriteLine ("Main thread: {0}", i);
Thread.Sleep(1000);
}
}
static void ThreadJob()
...{
for (int i=0; i < 10; i++)
...{
Console.WriteLine ("Other thread: {0}", i);
Thread.Sleep(500);
}
}
} 结果:
Main thread: 0
Other thread: 0
Other thread: 1
Main thread: 1
Other thread: 2
Other thread: 3
Main thread: 2
Other thread: 4
Other thread: 5
Main thread: 3
Other thread: 6
Other thread: 7
Main thread: 4
Other thread: 8
Other thread: 9
// UsingDelegate.cs
------------------------------------
using System;
using System.Threading;
public class Test
... {
static void Main()
...{
Counter foo = new Counter();
ThreadStart job = new ThreadStart(foo.Count);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Console.WriteLine ("Main thread: {0}", i);
Thread.Sleep(1000);
}
}
}
public class Counter
... {
public void Count()
...{
for (int i=0; i < 10; i++) ...{ Console.WriteLine ("Other thread: {0}", i);
Thread.Sleep(500);
}
}
}
二、线程中的参数传递
使用类、类的方法或类的属性都可以向线程传递参数:{ string url; public UrlDownloader ( string url) { this.url = url; } public void Download() {
public class UrlDownloader
WebClient wc = new WebClient();
Console.WriteLine("Downloading " + url); byte[] buffer = wc.DownloadData (url); string download = Encoding.ASCII.GetString(buffer); Console.WriteLine(download); Console.WriteLine("Download successful.");
//这里你可以将download进行保存等处理...... } } [... 在另一个类中使用它们...] UrlDownloader downloader = new UrlDownloader (yourUrl); new Thread ( new ThreadStart (downloader.Download)).Start();
注意参数是如何传递的。
在.NET 2.0中还可以这样:
(CODE-BESIDE)
方式一:
ThreadStart starter = delegate { Download(yourUrl); }); new Thread(starter).Start();
//使用线程池WaitCallback callback = delegate (object state) { Download ((string)state); }; ThreadPool.QueueUserWorkItem (callback, yourUrl);方式二(使用ParameterizedThreadStart):Thread t = new Thread (new ParameterizedThreadStart(DownloadUrl)); t.Start (myUrl); static void DownloadUrl(object url) { // ....
}
三、线程内部是如何进行的?
看一下以下两个例子的运行结果:
// TestThread.csusing System;
using System.Threading;
public class Test
... {
static int count=0;
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
count++;
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
count++;
}
}
}
// InnerDataThread.csusing System;
using System.Threading;
public class Test
... {
static int count=0;
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
int tmp = count;
Console.WriteLine ("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine ("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine ("Written count={0}", tmp);
Thread.Sleep(30);
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
int tmp = count;
Console.WriteLine (" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine (" Incremented tmp to {0}", tmp);
Thread.Sleep(10);
count = tmp;
Console.WriteLine (" Written count={0}", tmp);
Thread.Sleep(40);
}
}
}
Read count=0 Read count=0 Incremented tmp to 1 Written count=1 Incremented tmp to 1 Written count=1 Read count=1 Incremented tmp to 2 Read count=1 Written count=2 Read count=2 Incremented tmp to 2 Incremented tmp to 3 Written count=2 Written count=3 Read count=3 Read count=3 Incremented tmp to 4 Incremented tmp to 4 Written count=4 Written count=4 Read count=4 Read count=4 Incremented tmp to 5 Written count=5 Incremented tmp to 5 Written count=5 Read count=5 Incremented tmp to 6 Written count=6 Final count: 6 |
再比较下面这个例子:
//
使用Monitor.Enter/Exit
// MonitorThread.cs
using System;
using System.Threading;
public class Test
... {
static int count=0;
static readonly object countLock = new object();
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Monitor.Enter(countLock);
int tmp = count;
Console.WriteLine ("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine ("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine ("Written count={0}", tmp);
Monitor.Exit(countLock);
Thread.Sleep(30);
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
Monitor.Enter(countLock);
int tmp = count;
Console.WriteLine (" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine (" Incremented tmp to {0}", tmp);
Thread.Sleep(10);
count = tmp;
Console.WriteLine (" Written count={0}", tmp);
Monitor.Exit(countLock);
Thread.Sleep(40);
}
}
}
// MonitorThread.cs
using System;
using System.Threading;
public class Test
... {
static int count=0;
static readonly object countLock = new object();
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
Monitor.Enter(countLock);
int tmp = count;
Console.WriteLine ("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine ("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine ("Written count={0}", tmp);
Monitor.Exit(countLock);
Thread.Sleep(30);
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
Monitor.Enter(countLock);
int tmp = count;
Console.WriteLine (" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine (" Incremented tmp to {0}", tmp);
Thread.Sleep(10);
count = tmp;
Console.WriteLine (" Written count={0}", tmp);
Monitor.Exit(countLock);
Thread.Sleep(40);
}
}
}
结果与上例InnerDataThread.cs是不一样的,原因就在于Monitor的使用了。
Read count=0 Incremented tmp to 1 Written count=1 Read count=1 Incremented tmp to 2 Written count=2 Read count=2 Incremented tmp to 3 Written count=3 Read count=3 Incremented tmp to 4 Written count=4 Read count=4 Incremented tmp to 5 Written count=5 Read count=5 Incremented tmp to 6 Written count=6 Read count=6 Incremented tmp to 7 Written count=7 Read count=7 Incremented tmp to 8 Written count=8 Read count=8 Incremented tmp to 9 Written count=9 Read count=9 Incremented tmp to 10 Written count=10 Final count: 10 |
下面使用lock来锁定线程:
//
LockThread.cs
using System;
using System.Threading;
public class Test
... {
static int count=0;
static readonly object countLock = new object();
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
lock (countLock)
...{
int tmp = count;
Console.WriteLine ("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine ("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine ("Written count={0}", tmp);
}
Thread.Sleep(30);
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
lock (countLock)
...{
int tmp = count;
Console.WriteLine (" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine (" Incremented tmp to {0}", tmp);
if (count < 100)
throw new Exception();
Thread.Sleep(10);
count = tmp;
Console.WriteLine (" Written count={0}", tmp);
}
Thread.Sleep(40);
}
}
}
using System;
using System.Threading;
public class Test
... {
static int count=0;
static readonly object countLock = new object();
static void Main()
...{
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
for (int i=0; i < 5; i++)
...{
lock (countLock)
...{
int tmp = count;
Console.WriteLine ("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine ("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine ("Written count={0}", tmp);
}
Thread.Sleep(30);
}
thread.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void ThreadJob()
...{
for (int i=0; i < 5; i++)
...{
lock (countLock)
...{
int tmp = count;
Console.WriteLine (" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine (" Incremented tmp to {0}", tmp);
if (count < 100)
throw new Exception();
Thread.Sleep(10);
count = tmp;
Console.WriteLine (" Written count={0}", tmp);
}
Thread.Sleep(40);
}
}
}
结果如何?与MonitorThread.cs比较一下,再想想看。
四、死锁
// DeadLockSample.cs
// 分析一下为什么会发生死锁?
using
System;
using System.Threading;
public class Test
... {
static readonly object firstLock = new object();
static readonly object secondLock = new object();
static void Main()
...{
new Thread(new ThreadStart(ThreadJob)).Start();
// Wait until we're fairly sure the other thread
// has grabbed firstLock
Thread.Sleep(500);
Console.WriteLine ("Locking secondLock");
lock (secondLock)
...{
Console.WriteLine ("Locked secondLock");
Console.WriteLine ("Locking firstLock");
lock (firstLock)
...{
Console.WriteLine ("Locked firstLock");
}
Console.WriteLine ("Released firstLock");
}
Console.WriteLine("Released secondLock");
}
static void ThreadJob()
...{
Console.WriteLine (" Locking firstLock");
lock (firstLock)
...{
Console.WriteLine(" Locked firstLock");
// Wait until we're fairly sure the first thread
// has grabbed secondLock
Thread.Sleep(1000);
Console.WriteLine(" Locking secondLock");
lock (secondLock)
...{
Console.WriteLine(" Locked secondLock");
}
Console.WriteLine (" Released secondLock");
}
Console.WriteLine(" Released firstLock");
}
}
using System.Threading;
public class Test
... {
static readonly object firstLock = new object();
static readonly object secondLock = new object();
static void Main()
...{
new Thread(new ThreadStart(ThreadJob)).Start();
// Wait until we're fairly sure the other thread
// has grabbed firstLock
Thread.Sleep(500);
Console.WriteLine ("Locking secondLock");
lock (secondLock)
...{
Console.WriteLine ("Locked secondLock");
Console.WriteLine ("Locking firstLock");
lock (firstLock)
...{
Console.WriteLine ("Locked firstLock");
}
Console.WriteLine ("Released firstLock");
}
Console.WriteLine("Released secondLock");
}
static void ThreadJob()
...{
Console.WriteLine (" Locking firstLock");
lock (firstLock)
...{
Console.WriteLine(" Locked firstLock");
// Wait until we're fairly sure the first thread
// has grabbed secondLock
Thread.Sleep(1000);
Console.WriteLine(" Locking secondLock");
lock (secondLock)
...{
Console.WriteLine(" Locked secondLock");
}
Console.WriteLine (" Released secondLock");
}
Console.WriteLine(" Released firstLock");
}
}
Locking firstLock Locked firstLock Locking secondLock Locked secondLock Locking firstLock Locking secondLock |
因应之道,使用Queue和Monitor:
//
QueueMonitorThread.cs
using System;
using System.Collections;
using System.Threading;
public class Test
... {
static ProducerConsumer queue;
static void Main()
...{
queue = new ProducerConsumer();
new Thread(new ThreadStart(ConsumerJob)).Start();
Random rng = new Random(0);
for (int i=0; i < 10; i++)
...{
Console.WriteLine ("Producing {0}", i);
queue.Produce(i);
Thread.Sleep(rng.Next(1000));
}
}
static void ConsumerJob()
...{
// Make sure we get a different random seed from the
// first thread
Random rng = new Random(1);
// We happen to know we've only got 10
// items to receive
for (int i=0; i < 10; i++)
...{
object o = queue.Consume();
Console.WriteLine (" Consuming {0}", o);
Thread.Sleep(rng.Next(1000));
}
}
}
public class ProducerConsumer
... {
readonly object listLock = new object();
Queue queue = new Queue();
public void Produce(object o)
...{
lock (listLock)
...{
queue.Enqueue(o);
if (queue.Count==1)
...{
Monitor.Pulse(listLock);
}
}
}
public object Consume()
...{
lock (listLock)
...{
while (queue.Count==0)
...{
Monitor.Wait(listLock);
}
return queue.Dequeue();
}
}
}
using System;
using System.Collections;
using System.Threading;
public class Test
... {
static ProducerConsumer queue;
static void Main()
...{
queue = new ProducerConsumer();
new Thread(new ThreadStart(ConsumerJob)).Start();
Random rng = new Random(0);
for (int i=0; i < 10; i++)
...{
Console.WriteLine ("Producing {0}", i);
queue.Produce(i);
Thread.Sleep(rng.Next(1000));
}
}
static void ConsumerJob()
...{
// Make sure we get a different random seed from the
// first thread
Random rng = new Random(1);
// We happen to know we've only got 10
// items to receive
for (int i=0; i < 10; i++)
...{
object o = queue.Consume();
Console.WriteLine (" Consuming {0}", o);
Thread.Sleep(rng.Next(1000));
}
}
}
public class ProducerConsumer
... {
readonly object listLock = new object();
Queue queue = new Queue();
public void Produce(object o)
...{
lock (listLock)
...{
queue.Enqueue(o);
if (queue.Count==1)
...{
Monitor.Pulse(listLock);
}
}
}
public object Consume()
...{
lock (listLock)
...{
while (queue.Count==0)
...{
Monitor.Wait(listLock);
}
return queue.Dequeue();
}
}
}
Producing 0 Consuming 0 Producing 1 Consuming 1 Producing 2 Consuming 2 Producing 3 Consuming 3 Producing 4 Producing 5 Consuming 4 Producing 6 Consuming 5 Consuming 6 Producing 7 Consuming 7 Producing 8 Consuming 8 Producing 9 Consuming 9 |