漫谈C++ Builder多线程编程技术

http://tech.163.com/school · 2005-05-31 10:52:34 · 来源: 计算机与信息技术

  摘 要:本文简单介绍了Windows环境下进行多线程编程的意义,重点讨论了C++Builder环境下开发多线程应用程序这一问题,并通过实现生产者-消费者问题,帮我们更好地理解同步概念及其实现方法。

  关键词:多线程;同步;生产者-消费者;C++Builder

  线程之可行性

  在很多情况下,可能需要为程序创建线程。这里给出其中一些可能性:

  (1)如果创建的是一个多文档接口(Multiple 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) 属性:

  ·Priority:优先级属性。可以设置线程的优先级。

  ·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;
  Int j;
  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_size;
  Form1->Product [j] = i;
  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 ----
  Int j;
  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++ Builder多线程编程技术相关推荐

  1. java超线程_超线程多核心下Java多线程编程技术分析

    在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述超线程多核心下Java多线程编程技术分析,更多Java专业知识,广州疯狂 ...

  2. Windows下多线程编程技术及其实现

    本文首先讨论16位Windows下不具备的线程的概念,然后着重讲述在32位Windows 95环境下多线程的编程技术,最后给出利用该技术的一个实例,即基于Windows95下TCP/IP的可视电话的实 ...

  3. Android开发中的多线程编程技术

    Android开发中的多线程编程技术 [IT168技术]多线程这个令人生畏的"洪水猛兽",很多人谈起多线程都心存畏惧.在Android开发过程中,多线程真的很难吗?多线程程序的&q ...

  4. iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)

    简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...

  5. 多线程编程技术开发资料

    多线程编程技术开发资料 目录 Win32 多线程的性能(1)... 1 Win32 多线程的性能(2)... 10 关于多线程的一些细节... 23 用VC++5.0 实 现 多 线 程 的 调 度  ...

  6. Android 开发中的多线程编程技术

    此文章来自"Intel Software"应用开发 多线程这个令人生畏的"洪水猛兽",很多人谈起多线程都心存畏惧.在Android开发过程中,多线程真的很难吗? ...

  7. iOS多线程编程技术之NSThread、Cocoa NSOperation、GCD

    iOS有三种多线程编程的技术,分别是:NSThread .Cocoa NSOperation .GCD. 这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使 ...

  8. 【转】iOS多线程编程技术之NSThread、Cocoa NSOperation、GCD

    转自容芳志的博客 简介 iOS有三种多线程编程的技术,分别是: (一)NSThread  (二)Cocoa NSOperation (三)GCD(全称:Grand Central Dispatch) ...

  9. python多线程编程技术主要应用_python多线程,多进程编程。

    进程,是目前计算机中为应用程序分配资源的最小单位: 线程,是目前计算机中运行应用程序的最小单位: 在实际系统中,其实进程都是被分为线程来实现的,所以参与时间片轮转的是线程: 但是管理应用程序的资源的单 ...

最新文章

  1. python 打包egg_将Python程序打包到egg或WHL安装包或exe包中,把,python,成,或者,whl
  2. 多线程调用同一个方法,局部变量会共享吗
  3. oracle带输出参数存储,oracle带输入输出参数存储过程(包括sql分页功能)
  4. 软件构造学习笔记-第十三周
  5. 项目学生:带有Jersey的Web服务服务器
  6. windows linux内核版本,微软决定在Windows10中发布一个完整的Linux内核
  7. 2019年密码与安全新技术讲座-课程总结报告
  8. 扒一扒「清华系」的 AI 安防大佬们
  9. 机器学习笔记:t-SNE
  10. Twaver-HTML5基础学习(13)连线(Link)连线的绑定与展开
  11. 爬虫实例 8684公交网-太原公交线路信息
  12. 笔记本如何关闭屏幕亮度自动调节(解决切换界面时屏幕忽明忽暗的问题)
  13. IFIX数据写入html,iFIX常见问题问答.doc
  14. 视频转换生成二维码,扫码直接播放,在线制作,一键上传
  15. 机器的崛起:隐藏的控制论历史(二)
  16. 简历项目描述过程详解
  17. 《 中国高校鄙视链大全 》
  18. 【Aegisub相关】_G 简化代码写法的有效范围
  19. QuartusII13.0 bdf文件中元器件名称显示不完整解决方法
  20. 一零四、前端性能优化详解

热门文章

  1. 【转】WSS3.0开发--你还在为写CAML痛苦吗?
  2. NYOJ 61 传纸条(一)
  3. redis相关知识记录整理
  4. python中list转csv的两种方法
  5. 教你查看Windows 7的详细系统版本号
  6. EF中 GroupJoin 与 Join
  7. 弄懂CNN,然后提升准确率4.21-4.27
  8. 杂项-权限管理:RBAC
  9. js中json法创建对象(json里面的:相当于js里面的=)
  10. 【29.70%】【codeforces 723D】Lakes in Berland