【聚杰网C++】实例解析C++/CLI线程之多任务
一个重入的函数可由多个线程安全地并行执行。当线程开始执行一个函数时,在函数中分配的所有数据都来自栈或堆,但无论如何,对此调用来说,都是唯一的。如果在另一个线程仍处于工作状态时,本线程开始执行同一个函数,那么,每个线程中的数据都是相互独立的。然而,如果函数访问线程间共享的变量或文件时,则必须使用某些同步方法。
创建线程
在例1中,主线程创建了两个其他的线程,这三个线程并行运行,并且未进行同步。在线程间并未共享数据,且当最后一个线程结束时,主进程也结束了。
例1:
| using namespace System; using namespace System::Threading; public ref class ThreadX { int loopStart; int loopEnd; int dispFrequency; public: ThreadX(int startValue, int endValue, int frequency) { loopStart = startValue; loopEnd = endValue; dispFrequency = frequency; } /*1*/ void ThreadEntryPoint() { /*2*/ String^ threadName = Thread::CurrentThread->Name; for (int i = loopStart; i <= loopEnd; ++i) { if (i % dispFrequency == 0) { Console::WriteLine("{0}: i = {1,10}", threadName, i); } } Console::WriteLine("{0} thread terminating", threadName); } }; int main() { /*3a*/ ThreadX^ o1 = gcnew ThreadX(0, 1000000, 200000); /*3b*/ Thread^ t1 = gcnew Thread(gcnew ThreadStart(o1, &ThreadX::ThreadEntryPoint)); /*3c*/ t1->Name = "t1"; /*4a*/ ThreadX^ o2 = gcnew ThreadX(-1000000, 0, 200000); /*4b*/ Thread^ t2 = gcnew Thread(gcnew ThreadStart(o2, &ThreadX::ThreadEntryPoint)); /*4c*/ t2->Name = "t2"; /*5*/ t1->Start(); /*6*/ t2->Start(); Console::WriteLine("Primary thread terminating"); } |
请看标记3a中第一条可执行语句,此处我们创建了一个用户自定义ThreadX类型的对象,这个类有一个构造函数、一个实例函数及三个字段。我们调用构造函数时,传递进一个开始、一个结束计数,及一个固定增量,其用于循环控制。
在标记3b中,创建了一个库类型System::Thread的对象,它源自命名空间System::Threading,可用此对象来创建一个新的线程,但是,在线程可以工作之前,它必须要知道从哪开始执行,所以传递给Thread构造函数一个System::ThreadStart代理类型,其可支持不接受参数的任意函数,且没有返回值(作为一个代理,它可封装进多个函数,在本例中,只指定了一个)。在上面的代码中,指定了线程由执行对象o1的ThreadEntryPoint实例函数开始,一旦开始之后,这个线程将会执行下去直到函数结束。最后,在标记3c中,随意使用了一个名称,以设置它的Name属性。
请看标记4a、4b及4c,第二个线程也一样,只不过设置了不同的循环控制及名称。
眼下,已构造了两个线程对象,但并未创建新的线程,也就是说,这些线程处于未激活状态。为激活一个线程,必须调用Thread中的Start函数,见标记5与6。通过调用进入点函数,这个函数启动了一个新的执行线程(对一个已经激活的函数调用Start将导致一个ThreadStateException类型异常)。两个新的线程都各自显示出它们的名称,并在循环中定时地显示它们的进度,因为每个线程都执行其自身的实例函数,所以每个线程都有其自己的实例数据成员集。
所有三个线程均写至标准输出,见插1,可看出线程中的输出是缠绕在一起的(当然,在后续的执行中,输出也可能有不同的顺序)。可见,主线程在其他两个线程启动之前就结束了,这证明了尽管主线程是其他线程的父类,但线程的生命期是无关的。虽然,例中使用的进入点函数无关紧要,但其可调用它可访问的任意其他函数。 插1:三个线程的缠绕输出





