Error_404_资源不存在
404. 抱歉! 您访问的资源不存在!
请确认您输入的网址是否正确,如果问题持续存在,请发邮件至contact与我们联系。 线程之可行性 在很多情况下,可能需要为程序创建线程。这里给出其中一些可能性: (1)假如创建的是一个多文档接口(Multle Document Interface,MDI)程序,那么为每个窗口分配一个线程就显得十分重要了,例如,对于一个通过多个Modem同时连接到多个主机的MDI通信程序而言,假如每个窗口都有它自己的线程来和一个主机通信,那么整个事情就简化很多。 (2)假如使用的是一台有多个处理器的机器,并希望充分利用所有可能获得的CPU资源,那么就需要将应用程序***成多个线程。Windows2000中CPU的划分单位为线程。因此,假如程序只包含一个线程,那么,默认环境下该程序只能使用其中一个CPU。但是,假如将此程序划分为多个线程,那么Windows2000就可以在不同的CPU上运行各个线程。 (3)在后台运行的某些任务的同时,要求用户还可以继续使用应用程序进行工作。利用线程很轻易实现这点。例如:可以将一些冗长的重算、页面格式化操作、文件的读写等活动都放在单独的线程中,使其在后台运行,而不会对用户造成影响。 同步 撰写多线程程序的一个最具挑战性的问题就是:如何让一个线程和另一个线程合作。这引出了一个非常重要的问题:同步。所谓同步是指进程、线程间相互通信时避免破坏各自数据的能力。Windows环境下的同步问题是由Win32系统的CPU时间片分配方式引起的。虽然在某一时刻,只有一个线程占用CPU(单CPU)时间,但是无法知道在什么时候,在什么地方线程被打断,这样如何保证线程之间不破坏彼此的数据就显得格外重要。同步问题是如此重要,也相当有趣,因而吸引了不少学者对他进行研究,由此产成了一系列经典的进程同步问题,其中较有代表性的是"生产者-消费者问题"、"读者-写者问题""哲学家进餐问题"等。在此,本文简要讨论了C++Builder平台下如何利用多线程编程技术实现"生产者-消费者"问题,帮助我们更好得理解同步概念及其实现方法。 生产者-消费者问题 生产者-消费者问题是一个闻名的进程同步问题。它描述的是:有一群生产者进程在生产消息,并将此消息提供给消费者进程去消费。为使生产者进程和消费者进程能并发进行,在他们之间设置了一个具有N个缓冲区的缓冲池,生产者进程可以将它所生产的消息放入一个缓冲区中,消费者进程可以从一个缓冲区中取得一个消息消费。尽管所有的生产者进程和消费者进程都是以异步方式进行的,但他们之间必须保持同步,即不答应消费者进程到一个空的缓冲区中去取消息,也不答应生产者进程向一个已装满消息且尚未被取走消息的缓冲区中投放消息。 C++Builder多线程应用程序编程基础 1、使用C++Builder提供的TThread类 VCL类库提供了用于线程编程的TThread类。在TThread类中封装了Windows中关于线程机制的WindowsAPI。对于大多数的应用程序来说,可在应用程序中使用线程对象来表示执行线程。线程对象通过封装使用线程所需的内容,简化了多线程应用程序的编写。注重,线程对象不答应控制线程堆栈的大小或其安全属性。若需要控制这些,必须使用WindowsAPI的Create Thread()或Begin Thread()函数。TThread类有以下一些属性和方法: 1) 属性: ?iority:优先级属性。可以设置线程的优先级。 ?Return Value:返回值属性。当线程介绍时返回给其他线程一个数值。 ?Suspended:挂起属性。可以判定线程是否被挂起。 ?Terminated:结束属性。用来标志是否应该结束线程。 ?ThreadID:标识号属性。在整个系统中线程的标识号。使用Windows API函数时该属性非常有用。 2) 方法: ?Do Terminate:产生一个On Terminate事件,但是不结束线程的执行。 ?Resume:唤醒一个线程继续执行。 ?Suspend:挂起一个线程,要与Resume过程成对使用。 ?Synchronize:由主VCL线程调用的一个同步过程。 ?Terminate:将Terminate属性设置为True,中止线程的执行。 ?Wait For:等待线程的中止并返回Return Value属性的数值。 2、协调线程 在编写线程执行时运行的代码时,必须考虑到可能同步执行的其他线程的行为。非凡注重,避免两个线程试图同时使用相同的全局对象或变量。另外,一个线程中的代码会依靠其他线程执行任务的结果。 1) 避免同时访问 为避免在访问全局对象或变量时与其他线程发生冲突,可能需要暂停其他线程的执行,直到该线程代码完成操作。 (1)锁定对象。一些对象内置了锁定功能,以防止其他线程使用该对象的实例。例如,画布对象(TCanvas及其派生类)有一种Lock()函数可以防止其他线程访问画布,直到调用Unlock()函数。显然,这种方法只对部分类有效。 (2)使用重要区段。若对象没有提供内置的锁定功能,可使用重要区段。重要区段像门一样,每次只答应一个线程进入,要使用重要区段,需创建TCriticalSection的全局实例。TCriticalSection有两个函数:Acquire()(阻止其他线程执行该区域)及Release()(取消对其他线程的阻止)。 (3)使用多重读、独占写的同步器。当使用重要区段来保护全局内存时,每次只有一个线程可以使用该内存。这种保护可能会超出了需要,非凡是有一个经常读但很少写的对象或变量时更是如此。多个线程同时读相同内存但没有线程写内存是没有危险的。当有一些经常被读,但是很少写的全局变量时,可用TMultiReadExclusiveWriteSynchronizer对象保护它。这个对象和重要区段一样,但它答应多个线程同时读,只要没有线程写即可。每个需要读内存的线程首先要调用Begin Read()函数(确保当前无其他线程写内存),线程完成对保护内存读操作后,要调用End Read()函数。任何线程需要写保护内存必须调用Begin Write()函数(确保当前无其他线程读或写内存),完成对保护内存写操作后,调用End Write()函数。 (4)使用Synchronize函数:Void __fast call Synchronize (TThreadMethod &Method); 其中参数Method为一个不带参数的过程名。在这个不带参数的过程中是一些访问VCL的代码。我们可以在Execute过程中调用Synchronize过程来避免对VCL的并发访问。程序运行期间的具体过程实际上是由Synchronize过程来通知主线程,然后主线程在适当的时机来执行Synchronize过程的参数列表中的那个不带参数的过程。在多个线程的情况下,主线程将Synchronize过程发过来的通知放到消息队列中,然后逐个地响应这些消息。通过这种机制Synchronize实现了线程之间地同步。 2) 等待其他线程 若线程必须等待另一线程完成某项任务,可让线程临时中断执行。然后,要么等待另一线程完全执行结束,要么等待另一线程通知完成了该任务。 (1)等待线程执行结束 要等待另一线程执行结束,使用它地Wait For()函数。Wait For函数直到那个线程终止才返回,终止的方式要么完成了其Execute()函数,要么由于一个异常。 (2)等待任务完成。有时,只需要等待线程完成一些操作而不是等待线程执行结束。为此,可使用一个事件对象。事件对象(TEvent)应具有全局范围以便他们能够为所有线程可见。当一个线程完成一个被其他线程依靠的操作时,调用TEvent::Set Event()函数。Set Event发出一个信号,以便其他线程可以检查并得知操作完成。要关掉信号,则使用Reset Event()函数。 例如,当必须等待若干线程完成其执行而不是单个线程时。因为不知道哪个线程最后完成,也就不能对某个线程使用Wait For()函数。此时,可通过调用Set Event以在线程结束时累加计数值并在最后一个线程结束时发出信号以指示所有线程结束。 多线程应用程序编程实例 下面是一个实现"生产者-消费者问题"的多线程应用实例。在此例中,我们按上面介绍的方法构造了两个TThread的子类TProdUCerThread(生产者线程)和TCustomerThread(消费者线程),生产和消费的商品仅仅是一个整数。在协调生产和消费的过程中,重要区段(TCriticalSection)和事件(TEvent)得到了应用。生产者通过TEvent类的对象Begin Consume来通知消费者开始消费,而消费者通过TEent类的对象Begin Produce通知生产者开始生产。程序***有两个生产者,一个消费者。在两个生产者之间,通过TCriticalSection类的对象同步。其运行界面如图1所示。
图1 程序运行效果 主要源程序如下所示: 生产者线程:Void __fast call TProducerThread:: Execute (){ //---- Place thread code here ---- Int i = 0; I while(i&100) //每个生产者线程生产100个商品 { Sleep(1000);//延迟,为清楚得显示执行效果 if(Form1-&buffer_size & 0)//缓冲池不空,通知消费者消费 { Form1-&Begin Consumer-&Set Event (); } Form1-&Produce Guard-&Acquire (); i++; StrResult = IntToStr (i); J = Form1-&buffer_ Form1-&Product [j] = Form1-&buffer_size++; Synchronize(Show Result);//刷新界面,显示最新生产-消费状况 Form1-&Begin Consumer-&Set Event();//通知消费者消费 if(Form1-&buffer_size == 5)//缓冲池满,挂起生产者线程,直到通知再生产 { Form1-&Begin Produce-&Wait For (INFINITE); } Sleep (1000); Form1-&Produce Guard-&Release ();}While (Form1-&buffer_size & 0){ Form1-&Begin Consumer-&Set Event ();}} 消费者线程:Void __fast call TConsumerThread::Execute(){ //---- Place thread code here ---- I For (int i = 0;i & 200;i++) { Sleep(100); //延迟,为清楚得显示执行效果 Form1-&Begin Consumer-&Wait For(INFINITE);//挂起消费者线程,直到通知再消费 J = Form1-&buffer_size - 1; StrResult = IntToStr (Form1-&Product [j]); Form1-&buffer_size--; Synchronize(Show Result); //刷新界面,显示最新生产-消费状况 if(Form1-&buffer_size == 4)//缓冲池不再full,唤醒由于缓冲池full而挂起的生产者线程 { Form1-&Begin Produce-&Set Event (); } Sleep (100); }} 结论 本文讨论了多线程编程及其可行性,说明了在Windows环境下进行多线程编程的意义,并重点讨论了C++Builder平台下如何开发多线程应用程序这一问题,通过实现"生产者-消费者问题"这一闻名的进程同步问题,比较清楚地反映了在Windows环境下进行多线程编程技术及其实现的作用和效果。
更多内容请看C/C++技术专题&&编程开发手册专题,或
优质网站模板C++Builder的多线程编程中一些体会
C++Builder的多线程编程中一些体会
最近在写一个程序用到了多线程,所以对CB下的多线程有一定的学习。
现在把自己的一些心得讲一下。水平有限,写的很粗略,请大家见谅。
CB相对于VC来说,在CB下写多线程程序是很简单的。不仅是VCL中有TThread这个类。封装了那些关于多线程的WINDOW API.我觉得更方便的是他提供了直接访问主VCL线程中对象的能力。可以很容易的和主线程中的窗体,控件打交道。和单线程的方式没有太多区别。只是在有多个线程都要访问主线程中的对象(比如访问同一个窗体上的StringGrid)。只要用Thread的Synchronize方法来调用那段访问主VCL线程的代码(具体请看帮助),我们就不用担心访问冲突的问题了。而且对于多线程的同步和互斥,CB也对WINDOW 编程中那些机制进行了封装。比如对临界区CriticalSection封装为TCriticalSection.事件Event封装为TEvent.这些类相当简单好用。
下面就是我觉得比较重要的几点,供大家参考。
1.TThread的WaitFor方法。是等待一个线程返回。其返回值在这个线程里可以任意设定。以便在该线程返回的时候让调用他的线程知道他的运行情况。
在TThread的 OnTerminate事件中做线程的清除工作。他不是线程运行的一部分。
而是主VCL线程的一部分。所以在其中不能访问Thread的局部变量(如 int __thread i)
你可以把清楚代码写在这里,不用管现在在EXCUTE()方法执行到了哪个地方。
这么看起来有点类似于C++里的 finally 块的作用。
2.TEvent很重要。实现线程的同步。WaitFor(int Timeout)功能类似于WINDOW API WaitforSingleObject()。返回值包括:其中参数Timeout可以设为INFINITE表示永久等待,但这样,程序很容易死在这里。
wrSignaled 该事件发生(成功返回)。
wrTimeout 等待超时。
wrAbandoned 在该事件的超时期限到达前,该事件对象已经被毁灭了。。
wrError 在等待过程中有异常产生,要知道具体产生的错误要查看 TEvent的LastError属性。
3? TCriticalSection这个相当于WIN32编程中的临界区。
在多线程编程中,多个线程需要访问同一个公用变量的时候。
来保证访问的正确性。对公用变量访问的代码写在Enter();和Leave()之间。
比如有个公用变量 Count;以下代码 :
&TCriticalSection * pSection=new TCriticalSection();&& pSection-&Enter();& Count++;&& pSection-&Leave();
Enter()方法进入临界区,对其中的公用变量加锁。
Leave()方法离开临界区,对其中的公用变量解锁。
4.TMultiReadExclusiveWriteSynchronizer用来处理类似于多个生产者和多个消费者的问题。这里的消费者是指对公用变量进行读操作的线程。
生产者是对公用变量进行写操作的线程。
四个方法
BeginRead EndRead这两个方法用于消费者。
BeginWrite EndWrite这两个方法用于生产者。
使用的时候就是要把这个TMutiReadExclusiveWriteSynchronizer 定义一个全局变量。然后在其他线程中访问他。
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&2006年11月
日一二三四五六293031124567910111213141516171819202224252627282930123456789
IM在线情况:
留言簿(33)
随笔分类(214)
随笔档案(160)
积分与排名
阅读排行榜
评论排行榜