C#多线程编程

11 篇文章 0 订阅
//一个简单的示例
// 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);
        }

    }

}


二、线程中的参数传递
使用类、类的方法或类的属性都可以向线程传递参数:
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.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);
        }

    }

}


结果与上例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);
        }

    }

}


结果如何?与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");
    }

}

 

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

    }

}

 

 
 
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值