pb 8.0.3 注销线程就程序崩溃

jeremyruan 2012-10-25 10:46:42
最近使用pb 8.0.3 开发一程序需要串口通信,串口通讯代码就是从csdn下载的源码
1、首先定义一个线程对象uo_thread用于后台循环判断缓冲。每50ms读一次缓冲,有数据接收就接收,有发送就发送
of_start()
do while true
inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的sleep
loop

2、定义一个uo_pbcomm对象,在该对象的constructor中实例化线程uo_thread

if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
uo_thread_pbcomm = create uo_thread
SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObjectGet("pbcommobject",uo_thread_pbcomm) //用uo—thread引用共享对象uo_thread_pbcomm
uo_thread_pbcomm.of_setparent(this) //用中间对象给uo—thread中的实例变量赋值
uo_thread_pbcomm.Post of_start() //利用服务器推送技术,异步调用共享对象中的uf—start()

然后我该对象的destructor 函数中 销毁改该线程对象并释放内存
if isvalid(uo_thread_pbcomm) then
SharedObjectUnRegister("pbcommobject")
destroy uo_thread_pbcomm
end if

奇怪的是只要运行到 destroy uo_thread_pbcomm 程序必崩溃。由于该模块写在一个子窗口中,如果不运行destroy uo_thread_pbcomm释放内存,则关闭子窗口,则直接退出整个程序,并在程序退出后报错!

请大家帮忙看看




...全文
392 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
jeremyruan 2012-10-28
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 的回复:]

引用 18 楼 的回复:

可能么?线程不能共享全局变量。
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.……
[/Quote]


谢谢老大,已经搞定了,其实之前我已经看了你关于多线程的那篇博文起码几十遍,其实前几天我也按照你的博文设置线程的回调对象,但当时没有没有完全理解。再次感谢!!!!
也把我的思路分享一下

nvo_CallBack:
(none) Event ue_ThraedStart()
{
ib_Started=True
}
(none) Event ue_ThraedStop()
{
ib_Started=False
}
uo_thread of_Start():
in_CallBack.Event ue_ThreadStart()
do while true
yield()
if Not b_Start then exit
sleep(50)
loop
in_CallBack.Event ue_ThreadStop()

uo_thread of_stop()
b_start=false

uo_thread of_SetCallback(nvo_callbck callback) 设置线程 回调对象
in_callback =pp_callback


pb_comm Constructor event:

if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
uo_thread_pbcomm = create uo_thread
if isvalid(pp_callback) then destroy pp_callback
pp_callback=create nvo_CallBack //创建回调对象
SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObjectGet("pbcommobject",uo_thread_pbcomm) //用uo—thread引用共享对象
uo_thread_pbcomm.of_setparent(this) //用中间对象给uo—thread中的实例变量赋值

uo_thread_pbcomm.of_setcallback(pp_callback)//设置线程的回调对象

uo_thread_pbcomm.Post of_start() //利用服


uo_pbcomm Destructor Event:
if IsValid(uo_thread_pbcomm) then
uo_thread_pbcomm.Post of_Stop()

do while pp_CallBack.ib_Started //如果线程在运行则等待。

yield()

loop

SharedObjectUnRegister("pbcommobject") //注销线程并释放线程和回调对象内存
destroy uo_thread_pbcomm
destroy pp_CallBack
end if







jeremyruan 2012-10-28
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 的回复:]

引用 18 楼 的回复:

可能么?线程不能共享全局变量。
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.……
[/Quote]

谢谢老大,已经搞定了,其实之前我已经看了你关于多线程的那篇博文起码几十遍,其实前几天我也按照你的博文设置线程的回调对象,但当时没有没有完全理解。再次感谢!!!!
nvo_CallBack:
(none) Event ue_ThraedStart()
{
ib_Started=True
}
(none) Event ue_ThraedStop()
{
ib_Started=False
}
uo_thread of_Start():
in_CallBack.Event ue_ThreadStart()
do while true
yield()
if Not b_Start then exit
sleep(50)
loop
in_CallBack.Event ue_ThreadStop()
uo_thread of_setcallback(nvo_callbck callback) 设置线程 回调对象
in_callback =pp_callback


pb_comm Constructor event:
if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
uo_thread_pbcomm = create uo_thread
if isvalid(pp_callback) then destroy pp_callback
pp_callback=create nvo_CallBack //创建回调对象
SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObjectGet("pbcommobject",uo_thread_pbcomm) //用uo—thread引用共享对象
uo_thread_pbcomm.of_setparent(this) //用中间对象给uo—thread中的实例变量赋值
uo_thread_pbcomm.of_setcallback(pp_callback)//设置线程的回调对象
uo_thread_pbcomm.Post of_start() //利用服


uo_pbcomm Destructor Event:
if IsValid(uo_thread_pbcomm) then
uo_thread_pbcomm.Post of_Stop()
do while pp_CallBack.ib_Started //如果线程在运行则等待。
yield()
loop

SharedObjectUnRegister("pbcommobject")
destroy uo_thread_pbcomm
end if
A啦Dbit 2012-10-26
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 的回复:]

定义一个全局变量,作为一个信号量。读到它可以关闭的时候,销毁进程。
[/Quote]
全局变量没用的...它们是两个独立的线程...全局变量也是两套...

网上有这种相互操作的demo,主要是把主线程的对象传给子线程,然后子线程调用这个对象里的方法就可以操作主线程了
sbigwolf 2012-10-26
  • 打赏
  • 举报
回复
定义一个全局变量,作为一个信号量。读到它可以关闭的时候,销毁进程。
jeremyruan 2012-10-26
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]

当然最保险的方式应该是子线程空闲时向主线程发送一个信号,主线程通过这个信号来安全结束子线程,不过你也可以在子线程的of_stop()中用halt来主动结束自己(这个没测试)。
关于这方面的知识可以参考我的blog:
http://blog.csdn.net/gaoqiangz/article/details/6682895
[/Quote]
of_stop( ) 中用halt好像不行。
至于子线程发送信号给主线程,这个还不会搞啊。
路人甲cw 2012-10-26
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]

可能么?线程不能共享全局变量。
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的slee……
[/Quote]
在PB中全局变量确实不能互访,起码PB12+是这样的,这个我一开始以为是个BUG,后来发现可能真的是个BUG。。。
至于如何给主线程发送通知信号,其实可以用事件通知来做,在我的BLOG里有写,这里给一个简单的模型:

nvo_CallBack:
(none) Event ue_ThraedStart()
{
ib_Started=True
}
(none) Event ue_ThraedStop()
{
ib_Started=False
}
uo_thread of_Start():
in_CallBack.Event ue_ThreadStart()
do while true
yield()
if Not b_Start then exit
sleep(50)
loop
in_CallBack.Event ue_ThreadStop()

uo_pbcomm Destructor Event:
if IsValid(uo_thread_pbcomm) then
uo_thread_pbcomm.Post of_Stop()
do while in_CallBack.ib_Started
yield()
loop
SharedObjectUnRegister("pbcommobject")
destroy uo_thread_pbcomm
end if

jeremyruan 2012-10-26
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
// uo_thread_pbcomm = create uo_thread //这句可以不要SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObject……
[/Quote]

按照 这位兄弟的做了测试
uo_pbcomm对象的destructor 函数中 销毁改该线程对象并释放内存
if isvalid(uo_thread_pbcomm) then
SharedObjectUnRegister("pbcommobject")
destroy uo_thread_pbcomm
end if
上面这段代码在 uo_pbcomm对象的destructor 函数中 ,一定会出现问题
但如果写在 cb 按钮里面,而且必须用鼠标 点击这个按钮 能够正常终止子线程!!!!! 能够正常终止子线程!!!!! 如果在代码代码里面运行 triggerevent(clicked!) 有时都不能正常关闭子进程。

sbigwolf 2012-10-26
  • 打赏
  • 举报
回复
可能么?线程不能共享全局变量。
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的sleep
然后对象的destructor 函数中 销毁改该线程对象并释放内存
if isvalid(uo_thread_pbcomm) then
if gb_can_destroy = true then
SharedObjectUnRegister("pbcommobject")
destroy uo_thread_pbcomm
b_start = false
end if
end if

loop

A啦Dbit 2012-10-25
  • 打赏
  • 举报
回复
会不会是你的子线程还没退出...
路人甲cw 2012-10-25
  • 打赏
  • 举报
回复
当然最保险的方式应该是子线程空闲时向主线程发送一个信号,主线程通过这个信号来安全结束子线程,不过你也可以在子线程的of_stop()中用halt来主动结束自己(这个没测试)。
关于这方面的知识可以参考我的blog:
http://blog.csdn.net/gaoqiangz/article/details/6682895
路人甲cw 2012-10-25
  • 打赏
  • 举报
回复
原因在于你向子线程post一个of_stop()之后,但由于子线程后面还在执行slee()函数,所以of_start实际上处于等待状态,所以这个时候如果你强行Destory子线程那么将会发生这个错误,之所以你把时间设置短了没有出现问题那仅仅是因为主线程执行到Destroy的时候子线程的of_Start()已经退出了,错过了这个时间的重合点。解决方法很简单:
of_start()
do while true
yield()
if Not b_Start then exit
sleep(50)
loop
jeremyruan 2012-10-25
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
// uo_thread_pbcomm = create uo_thread //这句可以不要SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObject……
[/Quote]

有测试了,如把
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的sleep
loop
sleep(50) 其中的50ms改成2000ms则没有问题,如果 是50ms,关闭窗口后,直接程序假死

jeremyruan 2012-10-25
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

上面的改动不一定能解决问题,只是在程序里可以做如上的改动而已,还有:


uo_thread_pbcomm.Post of_start()

后面就可以写:
SharedObjectUnRegister("pbcommobject")


在PB 11.5 里我也遇到过相似的问题,后来,干脆就没有写 destroy XXXX 了。
但是 shareobjectunre……
[/Quote]

异步启动后立即 SharedObjectUnRegister("pbcommobject") 注销这个线程?
jeremyruan 2012-10-25
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
// uo_thread_pbcomm = create uo_thread //这句可以不要SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObject……
[/Quote]

大哥,这个是不行的啊,子线程仍然在工作啊

有啥好的方法,主线程传给变量给子线路,让他停止循环,比如在主线程中修改子线程 b_start 为false
wag_enu 2012-10-25
  • 打赏
  • 举报
回复
另,在编译的时候,不能编译成 dll 文件,而只能编译成 pbd ,不然,发布后的程序只能运行第一个线程。

这个也不知道是为什么。
wag_enu 2012-10-25
  • 打赏
  • 举报
回复
上面的改动不一定能解决问题,只是在程序里可以做如上的改动而已,还有:


uo_thread_pbcomm.Post of_start()

后面就可以写:
SharedObjectUnRegister("pbcommobject")


在PB 11.5 里我也遇到过相似的问题,后来,干脆就没有写 destroy XXXX 了。
但是 shareobjectunregister() 是要的。
wag_enu 2012-10-25
  • 打赏
  • 举报
回复
if isvalid(uo_thread_pbcomm) then destroy uo_thread_pbcomm
// uo_thread_pbcomm = create uo_thread //这句可以不要SharedObjectRegister("uo_thread","pbcommobject") //将uo—thread对象注册为pbcommobject
SharedObjectGet("pbcommobject",uo_thread_pbcomm) //用uo—thread引用共享对象uo_thread_pbcomm
uo_thread_pbcomm.of_setparent(this) //用中间对象给uo—thread中的实例变量赋值
uo_thread_pbcomm.Post of_start() //利用服务器推送技术,异步调用共享对象中的uf—start()

//////////////////////////////////
of_start()
do while b_start
yield() //这里加 yield()inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的sleep
loop

jeremyruan 2012-10-25
  • 打赏
  • 举报
回复
线程里面重新定义了 b_start
of_start()
do while b_start
inv_arg.triggerevent("ue_thread")
sleep(50)//此函数是api函数(Subroutine Sleep (ulong dwMilliseconds) Library "Kernel32.DLL"),非pb 自带的sleep
loop

有定义了of_stop()
b_start=false

然后
uo_trhead_pbcomm.post of_stop( )

任然无法让线程停止运行,不知道如何修改子线程里面b_start值。

呜呜。。。。。。。。

  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]
我试过了用全局变量都无法传递 让循环停止。
[/Quote]

Yield ( ) 可以让循环停止。
jeremyruan 2012-10-25
  • 打赏
  • 举报
回复
我试过了用全局变量都无法传递 让循环停止。
加载更多回复(1)

680

社区成员

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

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