线程是程序中独立的指令流。使用C#编写任何程序时,都有一个入口点:Main()方法。程序从main方法的第一条语句开始执行,知道这个方法返回为止。
运行在服务器上的应用程序中,等待客户请求的线程,称为侦听器线程。只要接收到请求,就把他传递给另一个工作线程,之后继续与客户通信。侦听器线程会立即返回,接收下一个客户发送的下一个请求。
进程包含资源,如window句柄、文件系统句柄或其他内核对象。每个进程都分配了虚拟内存。一个进程至少包含一个线程。操作系统会调度线程。线程有一个优先级、实际上正在处理的程序位置计数器、一个存储其局部变量的栈。每个线程都有自己的栈,但程序代码的内存和堆由一个进程的所有线程共享。这是一个进程的所有线程之间的通信非常快——该进程的所有线程都寻址相同的虚拟内存。线程是运行程序锁必须的。
理解线程异步,对于单CPU而言,在一个单位时间(也称时间片)内,只能执行一个线程,即只能干一件事。当一个线程的时间片用完时,系统会将该线程挂起,下一个时间内再执行另一个线程,如此,CPU以时间片为间隔在多个线程之间交替执行运算(其实这里还与每个线程的优先级有关,级别高的会优先处理)。由于交替时间间隔很短,所以造成了各个线程都在“同时”工作的假象;线程异步就是解决类似前面提到的执行耗时任务时界面控件不能使用的问题。如创建一个次线程去专门执行耗时的任务,而其他如界面控件响应这样的任务交给另一个线程执行(往往由主线程执行)。这样,两个线程之间通过线程调度器短时间(时间片)内的切换,就模拟出多个任务“同时”被执行的效果。
创建线程的一种简单方式是定义一个委托,并异步调用它。
Satatic int takesawhile(int data,int ms)
{
Console.writeline(“hello!”);
}
Public delegate int takesawhileDelegate(intdata,int ms);
Static void Main()
{
takesawhileDelegate d1=takesawhile;
IAsyncTesult ar=d1.BeginInvoke(1,3000,null,null);
While(!ar.IsCompleted)
{
Thread.sleep(50);
}
Int result=d1.EndInvoke(ar);//取得委托方法执行的返回值
Console.WriteLine(“result:”,resule);
}
输出:
hello!
Result:2
注:begininvoke和invoke的区别:invoke是同步调用,begininvoke是异步调用。
异步回调
BeginInvoke 方法启动异步调用。 该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。 第一个参数是一个 AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 返回一个 IAsyncResult,后者可用于监视异步调用的进度。
EndInvoke 方法检索异步调用的结果。 在调用 BeginInvoke 之后随时可以调用该方法。 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。 EndInvoke 参数包括需要异步执行方法中的out 和 ref 参数以及由BeginInvoke 返回的IAsyncResult 。
如果启动异步调用的线程不需要是处理结果的线程,则可以在调用完成时执行回调方法。 回调方法在ThreadPool 线程上执行。
若要使用回调方法,必须将表示回调方法的 AsyncCallback 委托传递给 BeginInvoke。 也可以传递包含回调方法要使用的信息的对象。 在回调方法中,可以将 IAsyncResult(回调方法的唯一参数)强制转换为 AsyncResult 对象。 然后,可以使用 AsyncResult.AsyncDelegate 属性获取已用于启动调用的委托,以便可以调用 EndInvoke。
using System;
usingSystem.Threading;
usingSystem.Runtime.Remoting.Messaging;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main()
{
// Create an instanceof the test class.
AsyncDemo ad = new AsyncDemo();
// Create thedelegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
int dummy = 0;
IAsyncResult result = caller.BeginInvoke(3000,
outdummy,
newAsyncCallback(CallbackMethod),
"The call executed on thread {0}, with return value\"{1}\".");
Console.WriteLine("Themain thread {0} continues to execute...",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(4000);
Console.WriteLine("The main thread ends.");
}
// The callbackmethod must have the same signature as the
// AsyncCallbackdelegate.
static void CallbackMethod(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncResult result = (AsyncResult) ar;
AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
// Retrieve theformat string that was passed as state
// information.
string formatString = (string)ar.AsyncState;
int threadId = 0;
// Call EndInvoke toretrieve the results.
string returnValue = caller.EndInvoke(outthreadId, ar);
// Use the formatstring to format the output message.
Console.WriteLine(formatString, threadId, returnValue);
}
}
}
/* This example produces output similar tothe following:
The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with returnvalue "My call time was 3000.".
The main thread ends.
*/
WaitHandle.WaitOne方法:阻止当前线程,直到当前 WaitHandle 收到信号。
您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。 异步调用完成时,WaitHandle 会收到信号;如果异步执行的方法没有结束,您可以通过调用 WaitOne 方法等待它执行结束。
(调用 EndInvoke 时不会自动关闭等待句柄。 如果释放对等待句柄的所有引用,则当垃圾回收功能回收等待句柄时,将释放系统资源。 若要在等待句柄使用完毕后立即释放系统资源,请调用WaitHandle.Close 方法来释放等待句柄。 显式释放可释放的对象时,垃圾回收的工作效率会更高。)
usingSystem;
usingSystem.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main()
{
// The asynchronousmethod puts the thread id here.
int threadId;
// Create an instanceof the test class.
AsyncDemo ad = new AsyncDemo();
// Create thedelegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate theasychronous call.
IAsyncResult result = caller.BeginInvoke(3000,
outthreadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Mainthread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// Wait for theWaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additionalprocessing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(outthreadId, result);
// Close the waithandle.
result.AsyncWaitHandle.Close();
Console.WriteLine("Thecall executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar tothe following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with returnvalue "My call time was 3000.".
*/