如何在pb中实现多线程

jqka007 2002-12-02 07:46:25
各位高手:
请问在pb中如何实现多线程。
...全文
394 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
888888888888 2002-12-10
  • 打赏
  • 举报
回复
关注
tchatcha 2002-12-10
  • 打赏
  • 举报
回复
多线程是指一个程序内部同时执行的多个流程,与单线程相比,它至少有两个方面的优点:第一,它可以更好地利用系统资源,比如CPU,若一个线程因I/O操作受阻,另一个线程仍可利用CPU来执行;第二,它更好地满足了客户的需求,因为挑剔的客户希望你开发的程序在显示动画的同时还能播放音乐、显示文件、下载网络文件等,这是单线程应用程序无法完成的。目前,支持多线程的开发工具主要有:Java、VC、Delphi和C++Builder。

  多线程强调的是一个进程内部有多个流程在同时执行,同时执行的概念相当于PB分布式计算中的异步处理。也就是说,只要我们在一个程序内部实现了异步处理,就相当于实现了多线程。分析至此,下一步该怎么做就不言而喻了:在一个应用程序内部实现分布式计算,使用服务器推送技术,异步执行共享对象中的函数。

  下面就编写一个Demo,介绍在PB中如何利用分布式计算技术来开发多线程应用程序,其程序结构如图1所示。uo—thread1和uo—thread2是类用户对象uo—thread的两个实例,uo—thread的功能是给实例变量li—Count自加5秒,自加的同时向中间对象uo—argv1和uo—argv2发送ue—thread消息。两个中间对象的功能是把ue—thread消息转化为ue—thread1和ue—thread2后发给主窗口w—main。

  程序结构

  主窗口接收到ue—thread1消息后,显示uo—thread1中自加变量的值,接收到ue—thread2后,显示uo—thread2中自加变量的值。在单线程中,uo—thread1先执行,5秒钟后uo—thread2开始执行,因此,前5秒内主窗口只能收到ue—thread1消息,后5秒内只能收到ue—thread2消息。在多线程中,uo—thread1和uo—thread2同时执行,因此w—main可以不断地收到ue—thread1和ue—thread2消息。

  1.设计用户对象uo—thread

  新建一个类用户对象,命名为uo—thread,添加如下两个实例变量:

  NonVisualObject inv—arg

  Long li—Count //自加变量

  创建如下三个用户函数:

  ⑴uf—start(),功能是:完成自加5秒并向中间对象发送ue—thread消息。脚本为:

  Time t0

  t0= Now() //获取当前时间

  Do While SecondsAfter(t0,Now())〈=5

  li—Count++//实例变量自加5秒

  inv—arg.TriggerEvent(′ue—thread′)

  //向中间对象发送ue—thread消息

  Loop

  ⑵uf—getcount(),功能是:获取自加变量的瞬间值。其脚本为:

  Return li—Count //返回实例变量

  ⑶uf—setparent(NonVisualObject nv—arg),调用时,使用中间对象为参数。脚本为:

  inv—arg=nv—arg

  //用中间对象给实例变量赋值

  2.设计中间对象uo—argv1和uo—argv2

  新建一个类用户对象,命名为uo—argv1,添加如下实例变量:

  Window win—arg

  创建用户函数uf—setparent(Window w—argv),调用时,用主窗口作为参数。其脚本为:

  win—arg=w—argv

  //用主窗口对象给实例变量赋值

  声明用户事件ue—thread,用于对uo—thread1发出的uo—thread消息进行响应,其脚本为:

  win—arg.TriggerEvent(″ue—thread1″)

  //向主窗口发送ue—thread1消息

  uo—argv2和uo—argv1完全一样,只需将uo—argv1中的ue—thread1改为uo—thread2即可。

  3.设计主窗口w—main

  主窗口外观如图2所示,凹下的三个控件分别为:st—thread1、st—thread2、st—time,分别用于显示uo—thread1和uo—thread2中自加变量的当前瞬间值和系统时间。声明两个用户事件:ue—thread1和ue—thread2,分别用于对中间对象发送来的ue—thread1和ue—thread2消息进行响应。ue—thread1事件处理代码为:

  图2 主窗口

  st—thread1.Text=String(uo—thread1.uf—getcount())

  ue—thread2事件的处理代码为:

  st—thread2.Text=String(uo—thread2.uf—getcount())

  w—main的Open事件代码为:

  uo—arg1 = Create uo—argv1

  //初始化中间对象的一个实例

  uo—arg2 = Create uo—argv2

  uo—arg1.uf—setParent(This) //给中间对象的实例变量赋值

  uo—arg2.uf—setParent(This)

  Timer(1) //启动定时器

  Timer事件处理代码为:

  st—time.Text=String(Now())//显示当前时间

  在“单线程”的Clicked事件中加入下列代码:

  SharedObjectUnRegister(″object1″)

  //注销先前注册过的共享对象object1

  SharedObjectUnRegister(″object2″)

  //注销先前注册过的共享对象object2

  If IsValid(uo—thread1) Then Destroy uo—thread1  //若uo—thread1已经存在,先删除

  If IsValid(uo—thread2) Then Destroy uo—thread2

  uo—thread1=Create uo—thread

  //初始化uo—thread1

  uo—thread2=Create uo—thread

  uo—thread1.uf—setparent(uo—argv1) //用中间对象给uo—thread1中的实例变量赋值

  uo—thread2.uf—setparent(uo—argv2)

  uo—thread1.Post uf—start() //执行uo—thread1中的uf—start()函数,完成后才执行下一句

  uo—thread2.Post uf—start()

  //上一条语句执行完成后才会执行

  在“多线程”的Clicked事件中加入下列代码:

  SharedObjectRegister(″uo—thread″,″object1″)

  //将uo—thread对象注册为object1

  SharedObjectRegister(″uo—thread″,″object2″)

  //将uo—thread对象注册为object2

  SharedObjectGet(″object1″,uo—thread1)

  //用uo—thread1引用共享对象object1

  SharedObjectGet(″object2″,uo—thread2)

  //用uo_thread2引用共享对象object2

  uo—thread1.uf—setparent(uo—argv1) //用中间对象给uo—thread1中的实例变量赋值

  uo—thread2.uf—setparent(uo—argv2)

  uo—thread1.Post uf—start() //利用服务器推送技术,异步调用共享对象中的uf—start()

  uo—thread2.Post uf—start()//相当于启动线程

  4.执行

BeanBoy 2002-12-10
  • 打赏
  • 举报
回复
同意 jackxrh(),在PB中使用SharedObjectRegister定义的共享对象,处理问题无法用Debug跟踪。
jackxrh 2002-12-03
  • 打赏
  • 举报
回复
你想在 PB 中用多线程 ? 到 vc++ 下面去自己写动态库吧 ..

别指望用 pb 的那个 玩意去做了 , 不然 , 出了问题都不知道该如何

debug ...
toutou 2002-12-03
  • 打赏
  • 举报
回复
pb实现多线程很麻烦的:
在版本6.0以前,pb是能够开发单线程商业软件的单线程应用程序开发工具。现在,随着共享对象的引入
使得能够用pb开发多线程应用程序。
背景:
共享对象的引入使得分布式pb服务器端程序能够同时然多个客户共享相同的数据。同样,也能提供给客
户多线程能力。
用处:
所有的共享对象必须是不可见的,这就意味着所有的编到应用程序中去的可见的功能都将在pb得主线程
中实现。当一个应用程序开始时pb的主线程自动执行。比方说:不可能有两个可见的计数器在不同的线程中
同时运行同时计数(见图1)。
不可见实例:
通常,当实例化一个pb的不可见对象时用CREATE语句(inv_shared = CREATE nvo_shared),这个语句
实例化了一个对象并建立了一个指向它的参考变量。还有一个新的函数来实例化一个共享对象,这就是:
SharedObjectRegister("nvo_Shared", "share1")
第一个参数是被共享的对象的类名,第二个参数是你想给的共享名(随便甚莫都行)
为了给共享对象得到一个参考变量可用另一个方法:

SharedObjectGet("share1",inv_Shared)
第一个参数是你在SharedObjectRegister() function中用到的共享名,第二个参数变量为
SharedObjectRegister() 函数 和第一个参数生命的是同一个类。

产生一个新线程:
一个新线程是用SharedObjectRegister函数产生的。但是在这个线程中得到一个异步执行的方法就必须
用Powerscript的 POST语句编码(例如:inv_shared.POST of_primeNumbers(1,1000))。当你执行一个共享对
象方法或函数或是事件时,若是没有POST关键字,引用的脚本就会运行在另一个线程中的方法,等待它结束
才继续运行下一行的代码。当你设置一个方法,它将被加到对象队列中并按顺序执行。大多数情况下,当当
前脚本结束时,方法被执行。因为它的返回值对引用的脚本不可用,故意放到单独的线程中去执行的方法不
应该有返回值,然而,如果它们确实有返回值将被忽略,不会有错误产生。

pb主线程和其他线程之间的通讯:

pb主线程能够在共享对象中直接执行一个方法(通过用由SharedObjectGet 函数建立的引用变量),但是
在调用线程时,共享对象甚莫都不能引用,调用对象时也是一样。为了解决这一限制,建立了接口对象,通
过引用它来传递共享对象。这种接口对象用来在共享对象和调用线程(pb主线程)之间提供接口(或通讯)。
接口对象的简单形式或许只有一个方法,它用来给frame's microhelp area(of_microhelpMsg(string))传递
一个字符串告诉用户已经完成了操作。
作为例子让我们再来看一下 of_primeNumbers 这个函数。我们家了第三个参数(一个nvo_Intfobj类),
我们用CREAT实例化这个在pb主线程中的nvo_Intfobj接口对象并用引用变量把它传递给of_primeNumbers h函
数作为第三个参数。在of_primeNumbers函数中的最后一个语句将执行街都对象的 of_microhelpMsg函数用一
个字符串告诉用户主要的数字已经计算完了。在这点上,必须有命令按钮或菜单项以便用户单击执行另一个
共享对象函数(of_getPrimeNumbers),这个函数在pb主线程中执行(因此它能返回数据)返回由
of_primeNumbers函数产生的基本数据。
当然,在这个设计中有一个用户接口问题,这需要用户做两件事:开始基本数据计算然后得到计算结果。
为了让基本数据得以计算并返回在只有一个用户交互作用时该怎莫做?
我们不能写一个先执行of_primeNumbers再执行of_getPrimeNumbers的脚本,因为of_primeNumber为了异
步运行必须被POST'ed,因此,of_primeNumbers 在of_getPrimeNumbers执行之前不会结束计算基本数据并返
回值。这个脚本有个时间选择问题。
我们能做的就是为借口对象些一个新方法以能够把数据返回给pb线程和调用对象,请看“返回数据”部
分。

返回数据:
方法of_primeNumbers(1,1000)计算从1到1000的所有奇数,但是,像我们干才学的那样,线程化的方法
不应该有返回值,,因此你或许会问调用脚本是如何获得计算的结果的呢?回答是,通过接口对象。将不得不
写一个新方法(of_returnPrimeNumbers)用来在of_primeNumbers末尾运行并得到of_primeNumbers的结果将
其作为一个参数。of_returnPrimeNUmbers依次会把奇数在调用对现时传递给另一个方法(在这个例子中是:
w_sales).

1. Cb_primeNumbers
2. Post inv_shared.of_primeNumbers(1,1000,inv_IntfObj)
3. Calculates all the prime numbers and saves them to an instance array
4. Post inv_IntfObj.of_returnPrimeNumber() which passes the prime numbers to
5. W_sales.of_returnPrimeNumbers which
6. Populates the DropDownListBox with prime number

图2
让我们描述一下在图2中发生了甚莫?

1.命令按钮cb_primeNumbers 是用户用来单击开始程序的
2.命令按钮cb_primeNumbers 设置了inv_shared.of_primeNumbers 并传递三个参数(包括一个给接口对象的
参数)
3.函数inv_shared.of_primeNumbers计算所有传递给它的参数范围内存在的奇数并把它们存在一个实例数阻

4.函数inv_shared.of_primeNumbers调用函数inv_Intfobj.of_returnPrimeNumbers并把计算好的奇数数组传
递给它
5.函数 w_sales.of_returnPrimeNumbers 作为输入参数的到这些奇数
6.用它们组装下拉列表框

存储空间:
所有的实例化的共享对象用 SharedObjectRegister函数获得他们自己的存储空间,因此,他们只得到他
们的全局变量。共享对象在pb线程中或是任何共享对象线程中不能引用回任何对象。用于共享对象的线程为
应用程序用应用程序对象定义。共享对象会话有自己的应用程序全局变量的副本;然而,用于应用程序对象的
事件并没有被触发。因此,如果你想让共享对象执行任何建立操作(比如说初始化变量),你需要把这些操作
编码到共享对象的构造器事件中,因为应用程序对象的打开和连接开始事件见不会被触发。

方法队列:

作为pb主线程请求一个共享对象服务,这些请求顺序排列以避免可能发生的同时进入。这保证了只有一
个用户能够在固定时刻修改共享对象的内容。
如果想得到的功能是产生两个线程,每一个线程都同时运行一个共享对象方法,用
SharedObjectRegister函数产生两个对象就很必要了(即使它们是同一类)。每个共享对象的到自己的线程
和存储空间,如果它们同时执行,它们每一个都必须分别共享。

总结:

把所有上面提及的条件都考虑进去,典型的变多线程的方法是:

1.用SharedObjectRegister 函数实例化共享对象
2.用SharedObjectGet 函数给共享对象的到引用变量
3.建立一个接口对象,它将提供pb主线程和共享对象线程之间的通讯
4.设置一个方法作执行计算之用并把结果存到共享对象的实例变量里
5.从共享对象执行一个借口对象的方法来得到计算结果并作为参数传回给pb线程和调用对象显示
myclife 2002-12-02
  • 打赏
  • 举报
回复
搜一下以前的帖子,有相关的!

680

社区成员

发帖
与我相关
我的任务
社区描述
PowerBuilder API 调用
社区管理员
  • API 调用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧