Don't believe everything they've told you. Threads in C# are actually pretty easy.
别相信别人告诉你的所有的事。其实C#中的线程是很简单的。
A thread is an encapsulation of the flow of control in a program. you might be used to writing single-threaded programs - that is, programs that only execute one path through their code "at a time". If you have more than one thread, then code paths run "simultaneously".
线程是程序中的控制流程的封装。你可能已经习惯于写单线程程序,也就是,程序在它们的代码中一次只在一条路中执行。如果你多弄几个线程的话,代码运行可能会更加“同步”。
Why are some phrases above in quotes? In a typical process in which multiple threads exist, zero or more threads may actually be running at any one time. However on a machine that got n CPU's only one thread (actually) can run at any given time on each CPU, because each thread is a code path, each CPU can only run one code-action at a time. The appearance of running many more than n "simultaneously" is done by sharing the CPUs among threads.
在一个有着多线程的典型进程中,零个或更多线程在同时运行。但是,在有着N个CPU的机器上,一个线程只能在给定的时间上在一个CPU上运行,因为每个线程都是一个代码段,每个CPU一次只能运行一段代码。而看起来像是N个同时完成是线程间共享CPU时间片的效果。
In this example we will create another thread, we will try to implement a way to demonstrate the multithreaded way of working between the two threads we have, and at the end, we will sync the two threads (the main and the new one) for letting the new thread "wait" for a message before continuing.
这个例子里,我们将创建另一个线程,我们将用两个线程演示多线程的工作方式,最后,我们实现两个线程(主线程与新线程)同步,在新线程工作前必须等待消息。
To create a thread we need to add the System.Threading namespace. After that we need to understand that a thread has GOT to have a start point for its flow of control. The start point is a function, which should be in the same call or in a different one.
建立线程前我们必须引入System.Threading命名空间。然后我需要知道的是,线程得为控制流程建立一个起点。起点是一个函数,可以使一个相同的调用或其它。
Here you can see a function in the same class that is defined as the start point.
这里你可以看到在同一个类中定义的起点函数。
using System;
using System.Threading;
namespace ThreadingTester
{
class ThreadClass
{
public static void trmain()
{
for(int x=0;x < 10;x++)
{
Thread.Sleep(1000);
Console.WriteLine(x);
}
}
static void Main(string[] args)
{
Thread thrd1=new Thread(new ThreadStart(trmain));
thrd1.Start();
for(int x=0;x < 10;x++)
{
Thread.Sleep(900);
Console.WriteLine("Main :" + x);
}
}
}
}
Thread.Sleep(n) method puts the *this* thread into sleep for n milliseconds. You can see in this example, that in main we define a new thread, which its start point is the function trmain(), we then invoke the Start() method to begin the execution.
Thread.Sleep(n)方法把“this”线程置于n毫秒的休眠状态。你可以看看这个例子,在主函数我们定义了一个新的线程,其中它的起点是函数trmain(),我们然后包含了Start()方法开始执行。
If you run this example, you will know that the context switch between the threads (the process of letting a thread run in the CPU and then switching to another thread) lets the threads run almost together, I have placed the main thread to sleep 100 milliseconds less than the new thread in order to see which one thread runs "faster".
如果你运行这个例子,你就会了解线程间的切换(让CPU从运行一个线程转到另一个线程)让线程几乎同时运行,为了能看哪个线程运行更快我把主线程设置比新线程少100毫秒。
Now, a thread could be assigned with a name, before Starting the thread we could:
现在,在开始线程前,先给线程命名:
Thread thrd1=new Thread(new ThreadStart(trmain));
thrd1.Name="thread1";
thrd1.Start();
In the thread itself, we can take the name into usage by:
Thread tr = Thread.CurrentThread;
Console.WriteLine(tr.Name);
After we made that, imagine that we don’t want the new thread to run to the end immediately when we start it, say we want to start the new thread, let it run, in a certain point the new thread will pause and will wait for a message from the main thread (or from another thread).
在完成上面程序后,设想我们不想在一开始新线程就让它马上运行结束,也就是说,我们开启了一个新线程,让它运行,在某个特定的时间点,新线程暂停并等待从主线程(或其他线程)发来的消息。
We can do that by defining:
我们可以这样定义:
public static ManualResetEvent mre = new ManualResetEvent(false);
The ManualResetEvent is being created with false as start state, this class is being used to signal another thread, and to wait for one or more threads. Note that all threads should have access to that class in order to signal or listen on the same one.
ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。注意,为了通知或监听同一个线程,所有的其它线程都能访问那个类。
The waiting thread should:
等待线程这样写:
mre.WaitOne();
This will cause the waiting thread to pause indefinitely and wait for the class to be signaled.
这将引起等待线程无限期的阻塞并等待类来通知。
The signaling thread should:
发信号的线程应该这样:
mre.Set();
That will cause the class to be signaled as true, and the waiting thread will stop waiting. After signaling an event we can reset it to the base state by:
这样类就会被通知,值变成true,等待线程就会停止等待。在通知事件发生后,我们就可以使用下面语句把线程置于基状态:
mre.Reset();
Now lets implement all that in a single application:
现在让我们在程序执行一下:
using System;
using System.Threading;
namespace ThreadingTester
{
class ThreadClass
{
public static ManualResetEvent mre=new ManualResetEvent(false);
public static void trmain()
{
Thread tr = Thread.CurrentThread;
Console.WriteLine("thread: waiting for an event");
mre.WaitOne();
Console.WriteLine("thread: got an event");
for(int x=0;x < 10;x++)
{
Thread.Sleep(1000);
Console.WriteLine(tr.Name +": " + x);
}
}
static void Main(string[] args)
{
Thread thrd1=new Thread(new ThreadStart(trmain));
thrd1.Name="thread1";
thrd1.Start();
for(int x=0;x < 10;x++)
{
Thread.Sleep(900);
Console.WriteLine("Main :" + x);
if(5==x) mre.Set();
}
while(thrd1.IsAlive)
{
Thread.Sleep(1000);
Console.WriteLine("Main: waiting for thread to stop...");
}
}
}
}