Sharedobject与pb多线程

PB没有提供完整的多线程机制,只是提供了一种通过Sharedobject进行线程间通信的方式, (猜测)是以一个新线程启动另一个虚拟机, 并在其中实例化一个对象来运行一段程序(函数), 并在完成后执行回调。

这个具体概念目前还不是特别清晰, 从SharedObjectRegister函数的帮助中看, 原文写的是"opens a separate runtime session", 直译是打开一个单独的运行时会话。结合之前网上看到的分析, 在执行SharedObjectRegister函数时,就会启动一个新的虚拟机(pbvm)。所以所有的全局变量都是在各自的虚拟机中存在, 各有各的内存空间, 所以肯定无法用全局变量什么的进行线程间通信。

sharedobject这个命名很有意思, 从pb帮助上看, pb把在"新虚拟机"中创建的这个对象实例称为"共享对象", 应该是说这个新对象虽然不在当前主线程中, 但是被“共享”给当前主线程访问。这个应该是PB提供的一种专用的线程间通信机制吧。

具体来看, SharedObjectRegister函数, 传递了两个string参数, 第一个是类名, 第二个是实例名。这样,在新虚拟机中,就创建了一个该类的实例对象变量(在新虚拟机中实例化了一个对象)。那么怎样从当前线程中访问这个新线程中的“共享”对象呢,通过SharedObjectGet函数。

SharedObjectGet函数的目的, 就是把新线程中共享对象的引用赋值给当前主线程中的该类的一个实例变量, 从pb语法上理解, 也就是完成了一个指针变量间的赋值。只是在pb的帮助中, 使用的是引用(reference)这个概念,没有使用指针这个名词。 为了方便区分, 我们可以把主线程中这个对象引用变量, 称为"代理对象", 与"共享对象"相对应。

表面现象来猜测,pb对指向共享对象的指针(指向的是另一个虚拟机中的内存空间)进行了特殊的处理,可以在主线程直接访问,可能是某一种特殊的"代理机制"

如果不需要回调, 那么通过使用代理对象, 去调用位于另一个虚拟机中的"共享对象"的函数就可以了。

如果需要回调, 就要在定义共享变量的类时, 设置一个instance级的不可视对象, 这个(新虚拟机中的)实例变量实际上会用来存放主线程中的一个对象的引用, 也可以理解为新虚拟机中的"代理对象", 用来从新虚拟机中调用主线程中的对象函数

关于回调, 在pb的SharedObjectGet函数帮助中有例子, 实际是把主线程中的不可视对象的指针传递给了共享对象。例子中使用的是窗口级实例变量, 这个似乎有些问题, 因为在窗口关闭后, 这个回调用的对象指针就不知指向的是什么了。或者, pb通过引用计数什么的做单独的处理?

(23.1.19补充) 后来在"路人甲"大神的一篇文章中看到了更详细的分析:

1.所有在新线程中用到的全局变量, 都需要在新线程中进行初始化和赋值

2.主线程中创建的callback对象(nvo对象), 首先可以看作是一个传递数据的"容器", 但这些数据在新线程中访问是有限制的, 只有基本数据类型可以直接在新线程中访问(例如:数值型/字符串/字符/日期/时间/布尔/byte/blob这些, 同时也包括它们的数组, 还有只包含基本数据类型的结构变量)

3.callback对象中的方法, 在设计时, 往往可以分为两类,一类是用在主线程中, 多数用于向"容器"中填写数据, 另一类是在新线程中调用, 一般用于向主线程发送通知信息(通过post方式调用)

用于在主线程中调用的这些方法, 可以操作的数据类型, 当然是不受限制的, 可以直接访问"容器"中的"引用类型"的变量(对象);

 但是在新线程中调用的方法, 都不可以访问直接访问"容器"中的引用类型的对象

我自己曾经因为用"="赋值, 把"容器"中的结构变量成员, 向新线程中的本地结构变量直接赋值, 导致新线程异常中止, 具体原因是这个结构变量中, 包含有引用类型的对象

4.新线程中, 可以正常open窗口, 弹出messagebox窗口(阻塞)这些可视对象的, 
就像路神文章中说的, 只要你像使用单线程那样去使用新线程中的所有对象,
只要是在新线程中实例化的对象, 都是可以正常使用的

说到底, 还是主线程与新线程都是使用各自的地址空间, 所谓"井水不犯河水", 是不允许跨界访问的.
在主线程中创建的"容器"变量, 它的成员数据和方法, 都是在主线程的地址空间中, 只是把它的引用, 传递给了新线程, 所以才有上面的1.2.3条的限制, 新线程只能访问容器中的"基本数据类型"变量

   

注意事项: 1、主进程传入的对象或变量不管是不是ref线程内操作传入的引用都会影响主进程的对象或变量,且对象只能是nonvisualobject类型的。 2、基础变量如long等等都不能传引用ref会运行会报错 3、SharedObjectUnregister只是把SharedObjectDirectory中的去掉,实际内存不会释放必须destroy 4、主进程不能直接访问线程中的变量和对象,可以通过处理类私有的办法处理。 5、千万注意释放线程的时候一定要把线程里面的资源释放完,不然百分百卡死。比如一个线程里面有一个timing的计时器,如果不先stop(),直接destroy,百分百卡死。如果连接数据库或者其他接口时千万注意了!!!千万要在uf_stop()(此例子中的释放预留方法)里面把所有的资源都释放干净,资源都释放干净,源都释放干净,都释放干净,释放干净,放干净,干净,净…… 大体设计思路: 1、在主进程中建立一个“任务信息类”数组,其中包含“任务线程类”,一个任务对应一个线程。 2、在主进程中建立一个“任务管理类”,负责处理任务信息类。 简单举例: 1、新建1个“任务管理类”,再新建N“任务信息类”,将“任务信息类”赋值完成加入“任务管理类”,并创建一个“任务线程类”,此时线程开始running。 2、“任务线程类”中有一个内部timing类,监控自己是否执行完成,会改标志。“任务管理类”也有一个timing监控“任务信息类”和“任务线程类”的情况,把完成的结束。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值