多线程(翻译)


线程是个轻量级的进程,运用线程我们可以提高程序响应速度.要运用多线程我们必须得用Threading这个位于System下的命名空间.命名空间System.Threading里包含所有我们进行多线程所需要的类和方法.下面就让我们看第一个例子
using System;
using System.Threading;

public class MyThread
{

    
public static void Thread1()
    
{
        
for (int i = 0; i < 10; i++)
        
{
            Console.WriteLine(
"Thread1 {0}", i);
        }

    }


    
public static void Thread2()
    
{
        
for (int i = 0; i < 10; i++)
        
{
            Console.WriteLine(
"Thread2 {0}", i);
        }

    }

}


public class MyClass
{

    
public static void Main()
    
{
        Console.WriteLine(
"Before start thread");

        Thread tid1 
= new Thread(new ThreadStart(MyThread.Thread1));
        Thread tid2 
= new Thread(new ThreadStart(MyThread.Thread2));

        tid1.Start();
        tid2.Start();
    }

}

下面让我们解释以下这个代码片段
    这段代码中类MyThread包含两个静态方法Thread1和Thread2.开启线程必须实例化Thread类,该类的构造器里有类ThreadStart的引用,该构造器可以接受两种类型的表达式.创建线程类时当参数为Null时为ArgumentNullException当程序没有许可的时候是个表达式.(就是创建线程的时候可以带参数也可以不带参数)
    类Thread中ThreadStart的参数是创建线程类的方法名.Thread1由于是个静态方法因此我们用MyThread.Thread1作为线程构造器的参数而不必实例化MyThread类.Start()是开启线程的方法.上面代码输出结果为:
Before start thread
Thread1 
0
Thread1 
1
Thread1 
2
Thread1 
3
Thread1 
4
Thread1 
5
Thread1 
6
Thread1 
7
Thread1 
8
Thread1 
9
Thread2 
0
Thread2 
1
Thread2 
2
Thread2 
3
Thread2 
4
Thread2 
5
Thread2 
6
Thread2 
7
Thread2 
8
Thread2 
9
线程构造器的参数并不必须要求是静态方法,我们可以创建一个不是静态的方法但是我们必须实例化类.
using System;
using System.Threading;

public class MyThread
{

    
public void Thread1()
    
{
        
for (int i = 0; i < 10; i++)
        
{
            Console.WriteLine(
"Thread1 {0}", i);
        }

    }


    
public void Thread2()
    
{
        
for (int i = 0; i < 10; i++)
        
{
            Console.WriteLine(
"Thread2 {0}", i);
        }

    }

}


public class MyClass
{

    
public static void Main()
    
{
        Console.WriteLine(
"Before start thread");

        MyThread thr 
= new MyThread();

        Thread tid1 
= new Thread(new ThreadStart(thr.Thread1));
        Thread tid2 
= new Thread(new ThreadStart(thr.Thread2));

        tid1.Start();
        tid2.Start();
    }

}

这段代码的输出和第一个是相同的.
创建两个线程你不必要创建两个方法,你可以创建两个线程而仅仅创建一个线程方法,看如下这段代码

using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{
                        Console.WriteLine(
"Hello world {0}", i);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Start();
                tid2.Start();
        }

}
这里我们实例化了两个MyThread开启了两个线程.
   你也不必要在实例化Thread的构造函数中实例化ThreadStart,你可以实例化ThreadStart把结果作为参数传给Thread让我们看如下代码
using System;
using System.Threading;

public class MyThread
{

    
public void Thread1()
    
{
        
for (int i = 0; i < 10; i++)
        
{
            Console.WriteLine(
"Hello world {0}", i);
        }

    }

}


public class MyClass
{

    
public static void Main()
    
{
        Console.WriteLine(
"Before start thread");

        MyThread thr1 
= new MyThread();
        MyThread thr2 
= new MyThread();

        ThreadStart tStart1 
= new ThreadStart(thr1.Thread1);
        ThreadStart tStart2 
= new ThreadStart(thr2.Thread1);

        Thread tid1 
= new Thread(tStart1);
        Thread tid2 
= new Thread(tStart2);

        tid1.Start();
        tid2.Start();
    }

}
这段代码的输出和上一段输出是一样的.
Sleep方法暂停线程执行暂停一段时间.它是一个静态方法你不必要实例Thread类.他有两种重载方式,一种以毫秒为单位的参数一种以TimeSpan结构体为单位.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{
                        Console.WriteLine(
"Hello world " + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Start();
                tid2.Start();
        }

}
现在线程暂停1毫秒而第二个线程执行.结果如下:
Before start thread
Hello world 
0
Hello world 
0
Hello world 
1
Hello world 
1
Hello world 
2
Hello world 
2
Hello world 
3
Hello world 
3
Hello world 
4
Hello world 
4
Hello world 
5
Hello world 
5
Hello world 
6
Hello world 
6
Hello world 
7
Hello world 
7
Hello world 
8
Hello world 
8
Hello world 
9
Hello world 
9
现在看起来两个线程同时执行,下面是另一种重载sleep的方法.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        
int iHour = 0;
                        
int iMin = 0;
                        
int iSec = 1;

                        Console.WriteLine(
"Hello world " + i);
                        Thread.Sleep(
new TimeSpan(iHour, iMin, iSec) );
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Start();
                tid2.Start();
        }

}
TimeSpan有4种构造方式.第一中是指定特定时间片(The first take only one long paramater to a specified number of ticks)第二种有三个整形的参数时,分和秒.第三种有4个整形参数天,时,分和秒.第四种有5个整形参数天时分秒和毫秒.
Sleep方法有三种类型的表达式,当过时时间小于0为ArgumentException,当线程突然在睡眠中突然中断时为ThreadInterruptedException 当唤醒者有恰当权限时为SecurityException.
下面我们用一段代码展示Sleep参数为负时的情况.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        
int iHour = 0;
                        
int iMin = 0;
                        
int iSec = -1;

                        
try {
                                Console.WriteLine(
"Hello world " + i);
                                Thread.Sleep(
new TimeSpan(iHour, iMin, iSec) );
                        }

                        
catch (ArgumentException ae) {
                                Console.WriteLine(ae.Message );
                        }


                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Start();
                tid2.Start();
        }

}
Message是ArgumentException类的一个属性.它给我们异常的描述信息.在这段代码中他给我们如下信息:
Parameter Name: Argument must be greater than 0 and less than 2^31 - 1milliseconds.
我们可以指出线程的名字通过Thread的Name属性.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.Start();
                tid2.Start();
        }

}
在运行时中执行这段代码你会得到很多异常.让我们捕获Sleep中可能出现的异常.
using System;
using System.Threading;
using System.Security;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);

                        
try {
                                Thread.Sleep(
1);
                        }

                        
catch (ArgumentException ae) {
                                Console.WriteLine(ae.ToString() );
                        }

                        
catch (ThreadInterruptedException tie) {
                                Console.WriteLine(tie.ToString() );
                        }

                        
catch (SecurityException se) {
                                Console.WriteLine(se.ToString() );
                        }

                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.Start();
                tid2.Start();
        }

}
代码抛出三个异常。在第一行代码中我们多用了个System.Security命名空间.SecurityException类型就是在这个命名空间中定义的.
要想通过CurrentThread. CurrentThread这个Thread类的静态属性得到当前线程的名称的话我们必须引用thread.
当唤醒者没有恰当权限的时候运用这个属性会抛出SecurityException异常.这段代码输出如下:
Before start thread
Thread 
1=0
Thread 
2=0
Thread 
1=1
Thread 
2=1
Thread 
1=2
Thread 
2=2
Thread 
1=3
Thread 
2=3
Thread 
1=4
Thread 
2=4
Thread 
1=5
Thread 
2=5
Thread 
1=6
Thread 
2=6
Thread 
1=7
Thread 
2=7
Thread 
1=8
Thread 
2=8
Thread 
1=9
Thread 
2=9
有两个方法中指线程,Stop()和Abort().不要用Stop()因为这个方法会在将来一段时间执行.这种不确定性由.NET决定.Abort方法有两种重载形式.一种是没有参数一种是Object类型的参数.这种方法会抛出ThreadAbortException异常而不被捕获.看以下代码:
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);

                        
try {
                                Thread.Sleep(
1);
                        }

                        
catch (ArgumentException ae) {
                                Console.WriteLine(ae.ToString() );
                        }

                        
catch (ThreadInterruptedException tie) {
                                Console.WriteLine(tie.ToString() );
                        }

                        
catch (SecurityException se) {
                                Console.WriteLine(se.ToString() );
                        }

                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.Start();
                tid2.Start();

                
try {
                        tid1.Abort();
                        tid2.Abort();
                }

                
catch (ThreadAbortException tae) {
                        Console.WriteLine(tae.ToString() );
                }

                Console.WriteLine(
"End of Main");
        }

}
这段代码输出为:
Before start Thread
End of Main
这段输出清楚的告诉我们线程没有执行,既然线程能被阻止那么也可以唤醒线程.看如下代码:
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.Start();
                tid2.Start();

                tid1.Abort();
                tid2.Abort();

                Console.WriteLine(
"After Abort");

                tid1.Start();
                tid2.Start();

                Console.WriteLine(
"End of Main");
        }

}
这段代码抛出 System.Threading.ThreadStateException异常.现在让我们捕获异常并且幽雅的关闭程序而不是变态的终止代码.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                
try {
                        tid1.Start();
                        tid2.Start();
                }

                
catch (ThreadStateException te) {
                        Console.WriteLine(te.ToString() );
                }


                tid1.Abort();
                tid2.Abort();

                
try {
                        tid1.Start();
                        tid2.Start();
                }

                
catch (ThreadStateException te) {
                        Console.WriteLine(te.ToString() );
                }


                Console.WriteLine(
"End of Main");
        }

}
我们也可以用Join方法终止线程.它有三种重载形式.
First without parameter waits till the thread dies, second takes one int parameter and waits for the thread to die or for specified time to expire and third take a reference of an instance of the TimeSpan structure. See the following program.
using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                
try {
                        tid1.Start();
                        tid2.Start();
                }

                
catch (ThreadStateException te) {
                        Console.WriteLine(te.ToString() );
                }


                tid1.Join();
                tid2.Join(
new TimeSpan(001) );

                Console.WriteLine(
"End of Main");
        }

}

在这段代码中程序等待第一个线程直道它结束而对于第二个线程则等待1秒钟。

线程被执行有两种途径,前台和后台.后台线程随着程序终止而结束,而前台线程不等待程序的终止.我们可以用IsBackground属性执行线程.下面演示如何使用它.

using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.IsBackground 
= true;
                tid2.IsBackground 
= true;

                
try {
                        tid1.Start();
                        tid2.Start();
                }

                
catch (ThreadStateException te) {
                        Console.WriteLine(te.ToString() );
                }


                Thread.Sleep(
10);

                Console.WriteLine(
"End of Main");
        }

}
输出为
Before start thread
Thread 
1=0
Thread 
2=0
Thread 
1=1
Thread 
2=1
End of Main

This output shows when your application terminates that both background threads are also terminated.

We can also assign the priority of our thread. We can assign the priority of a thread by using ThreadPriority priority of the Thread class. This program shows the usage of the priority property of the thread.

using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {
                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(thr.Name 
+ "=" + i);
                        Thread.Sleep(
1);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();
                MyThread thr2 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );
                Thread tid2 
= new Thread(new ThreadStart(thr2.Thread1) );

                tid1.Name 
= "Thread 1";
                tid2.Name 
= "Thread 2";

                tid1.Priority 
= ThreadPriority.Highest;
                tid2.Priority 
= ThreadPriority.Lowest;

                
try {
                        tid1.Start();
                        tid2.Start();
                }

                
catch (ThreadStateException te) {
                        Console.WriteLine(te.ToString() );
                }


                tid1.Join();
                tid2.Join();

                Console.WriteLine(
"End of Main");
        }

}

The property of thread 1 is Highest and thread 2 is Lowest. Other possible priority levels are AboveNormal, BelowNormal and Normal.

The GetDomain() method returns the name of executable file in which the thread is executing. This is a static method so we use it with the name of class.

using System;
using System.Threading;

public class MyThread {

        
public void Thread1() {

        Console.WriteLine(Thread.GetDomain() );

                
for (int i = 0; i < 10; i++{

                        Thread thr 
= Thread.CurrentThread;
                        Console.WriteLine(i);
                }

        }

}


public class MyClass {

        
public static void Main() {
                Console.WriteLine(
"Before start thread");

                MyThread thr1 
= new MyThread();

                Thread tid1 
= new Thread(new ThreadStart(thr1.Thread1) );

                tid1.Start();

        }

}
The output of this program is
Before start thread
Name: prog16.exe
No context policies.

0
1
2
3
4
5
6
7
8
9
This is just an introduction to multithreaded programming using C#.
posted @ 2007-10-11 15:56  李占卫  阅读(471)  评论(0编辑  收藏  举报