有趣的多线程编程

一个简单的例子

//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);
        }
    }
}

                                                                                    线程中的参数传递

使用类、类的方法或类的属性都可以向线程传递参数:
public class UrlDownloader
{
string url;
public UrlDownloader (string url)
{
this.url = url;
}
public void Download()
{
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.cs
using 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.cs
using 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 ("\t\t\t\tRead count={0}", tmp);            Thread.Sleep(20);            tmp++;            Console.WriteLine ("\t\t\t\tIncremented tmp to {0}", tmp);            Thread.Sleep(10);            count = tmp;            Console.WriteLine ("\t\t\t\tWritten count={0}", tmp);            Thread.Sleep(40);        }    }}
Read count=0                                Read count=0                                Incremented tmp to 1                                Written count=1Incremented tmp to 1Written count=1                                Read count=1                                Incremented tmp to 2Read count=1                                Written count=2                                Read count=2Incremented tmp to 2                                Incremented tmp to 3Written count=2                                Written count=3Read count=3                                Read count=3Incremented tmp to 4                                Incremented tmp to 4                                Written count=4Written count=4                                Read count=4Read count=4                                Incremented tmp to 5                                Written count=5Incremented tmp to 5Written count=5Read count=5Incremented tmp to 6Written count=6Final 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 ("\t\t\t\tRead count={0}", tmp);
            Thread.Sleep(20);
            tmp++;
            Console.WriteLine ("\t\t\t\tIncremented tmp to {0}", tmp);
            Thread.Sleep(10);
            count = tmp;
            Console.WriteLine ("\t\t\t\tWritten count={0}", tmp);
            Monitor.Exit(countLock);
            Thread.Sleep(40);
        }
    }
}

结果与上例InnerDataThread.cs是不一样的,原因就在于Monitor的使用了。

Read count=0Incremented tmp to 1Written count=1                                Read count=1                                Incremented tmp to 2                                Written count=2Read count=2Incremented tmp to 3Written count=3                                Read count=3                                Incremented tmp to 4                                Written count=4Read count=4Incremented tmp to 5Written count=5                                Read count=5                                Incremented tmp to 6                                Written count=6Read count=6Incremented tmp to 7Written count=7                                Read count=7                                Incremented tmp to 8                                Written count=8Read count=8Incremented tmp to 9Written count=9                                Read count=9                                Incremented tmp to 10                                Written count=10Final 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 ("\t\t\t\tRead count={0}", tmp);
                Thread.Sleep(20);
                tmp++;
                Console.WriteLine ("\t\t\t\tIncremented tmp to {0}", tmp);
                if (count < 100)
                    throw new Exception();
                Thread.Sleep(10);
                count = tmp;
                Console.WriteLine ("\t\t\t\tWritten 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 ("\t\t\t\tLocking firstLock");        lock (firstLock)        {            Console.WriteLine("\t\t\t\tLocked firstLock");            // Wait until we're fairly sure the first thread            // has grabbed secondLock            Thread.Sleep(1000);            Console.WriteLine("\t\t\t\tLocking secondLock");            lock (secondLock)            {                Console.WriteLine("\t\t\t\tLocked secondLock");            }            Console.WriteLine ("\t\t\t\tReleased secondLock");        }        Console.WriteLine("\t\t\t\tReleased 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 ("\t\t\t\tConsuming {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


 

posted @ 2006-08-02 14:52  随风而逝  阅读(263)  评论(0编辑  收藏  举报