Project1

标题: 请教如何中止一个执行中的API [打印本页]

作者: 赛露休斯    时间: 2010-11-26 12:30
标题: 请教如何中止一个执行中的API
call了某个API后程序无响应,请教如何在call了5秒后中止并弹出“中止”的对话框
作者: 苏小脉    时间: 2010-11-26 14:34
在自己创建的一个 OS 线程中调用 API,另一个线程计时,超时中断调用 API 的线程。
作者: 赛露休斯    时间: 2010-11-26 14:36
我是创建一个线程执行,结果卡死
“另一个线程计时,超时中断调用 API 的线程”
这个不知道该怎么弄
作者: 禾西    时间: 2010-11-26 15:01
http://rpg.blue/thread-158680-1-1.html
作者: IamI    时间: 2010-11-26 18:16
本帖最后由 IamI 于 2010-11-26 18:20 编辑
  1. $t = Thread.new{sleep(5);print "超时";exit!;}
  2. sleep(2)
  3. $t.kill
复制代码
  1. $t = Thread.new{sleep(5);print "超时";exit!;}
  2. sleep(10)
  3. $t.kill
复制代码
事实证明一个叹号改变一切。
额,这里的例是强制退出。如果需要终止执行的API请将API提交另一线程,将现在的线程内容写入主线程,超时KILL之即可。
作者: 赛露休斯    时间: 2010-11-26 18:49
回复 IamI 的帖子

我把sleep(2)换成我那个可能卡死的API后,我发现只要执行到这个API后,包括下面的$t.kill都不会执行了,就卡在那个API上

作者: IamI    时间: 2010-11-26 19:57
额……线程中的弹框有没有出现?出现的话请按照之前的说明:
如果需要终止执行的API请将API提交另一线程,将现在的线程内容写入主线程,超时KILL之即可。

作者: 赛露休斯    时间: 2010-11-26 20:13
本帖最后由 赛露休斯 于 2010-11-26 20:14 编辑

加入线程也没用,我甚至在线程中创建线程把该API放进去依然没用,我用p命令测试,凡是执行到这个API就卡死,后面的命令全都不被执行
作者: 苏小脉    时间: 2010-11-26 21:05
本帖最后由 苏小脉 于 2010-11-27 05:55 编辑

不是说了么,让你创建 OS 线程。四五楼使用的是 Ruby 的线程,在 Ruby 1.8 中是属于万恶的绿色线程,在调用 OS 底层耗时的东西时无法进行上下文切换。1.8 自始至终都只有一个 OS 线程作为解释器在运行,执行权在交给底层的 API 后,自然解释器就完全失去了程序控制权,这时线程调度器自然也瘫痪了。

即便是使用了本地线程的 Ruby 1.9,由于有 GIL 的存在,当调用 API 的线程获得执行权后,就会对 GIL 进行加锁,所以虽然其它线程都是 OS 线程,但却都被锁在了外面,只能等待里面调用 API 的线程结束。
作者: 赛露休斯    时间: 2010-11-26 21:20
回复 苏小脉 的帖子

那问题就是如何在RMXP中创建 OS 线程了,能否举个例子?
作者: 苏小脉    时间: 2010-11-26 21:35
回复 赛露休斯 的帖子

用 RM 的话还得靠 DLL,因为 Win32API 线程处理是通过回调函数进行的,回调需要本地函数。

CreateThread 创建本地线程:
http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx

然后在 DLL 里写一个函数,把函数地址导出,传给 CreateThread 的 lpStartAddress 参数。
例子来不及写了,今天下班后如果没有人回复我就帮你写一个吧。
作者: 赛露休斯    时间: 2010-11-26 22:09
回复 苏小脉 的帖子

原来线程里还有这么多学问
太感谢了,那就拜托你了^_^

作者: 苏小脉    时间: 2010-11-27 11:48
一个例子:
  1. #pragma comment(linker, "/EXPORT:start_async_api=_start_async_api@0")
  2. #pragma comment(linker, "/EXPORT:abort_async_api=_abort_async_api@0")

  3. #include <Windows.h>

  4. static HANDLE hdl_thread;

  5. DWORD WINAPI thread_proc(void* param);

  6. void WINAPI start_async_api() {
  7.         hdl_thread = CreateThread(NULL, 0, thread_proc, 0, 0, NULL);
  8. }

  9. HANDLE WINAPI abort_async_api() {
  10.         TerminateThread(hdl_thread, 0);
  11. }

  12. DWORD WINAPI thread_proc(void* param) {
  13.         for (;;) MessageBox(NULL, "Loop loop and loop ...", "Infinity Inc.", MB_OK);
  14. }
复制代码
这里的 #pragma 指令是针对 MSVC 编译器写的,所以只能用 MSVC 编译;名称修饰是针对 C 的,所以不能生成按 C++ 生成代码;这些都是小节。
在 thread_proc 函数里可以去调用需要调用、耗时的 API,它会在一个独立的内核线程中运行。这里是一个无限弹出消息框的过程。
在 Ruby 中:

  1. start_async_api = Win32API.new('GeneralDllApp', 'start_async_api', 'v', 'v')
  2. abort_async_api = Win32API.new('GeneralDllApp', 'abort_async_api', 'v', 'v')

  3. start_async_api.call
  4. sleep 5
  5. abort_async_api.call
复制代码
一开始调用 start_async_api,创建线程并调用耗时 API,反复弹出消息框(当然,这里的弹出是同步的,下一个消息框弹出前会等待前一个消息框的销毁),但持续五秒后 Ruby 所在的线程调用 abort_async_api,终止了线程,于是不再弹出消息框。
作者: 赛露休斯    时间: 2010-11-27 16:37
回复 苏小脉 的帖子

只能大致看懂Ruby部分,MSVC看不懂。。。
那么现在该怎么做?
作者: 苏小脉    时间: 2010-11-28 02:49
回复 赛露休斯 的帖子

代码都给你了,直接编译为 DLL 即可。
作者: 赛露休斯    时间: 2010-11-28 13:42
回复 苏小脉 的帖子

不会编译 DLL 呢
我是选择了一个空项目的win32dll项目,然后直接添加一个cpp把代码放进去编译,结果。。。
error C2664: “MessageBoxW”: 不能将参数 2 从“const char [23]”转换为“LPCWSTR”
与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换

一窍不通,完全不知道该怎么弄呢
作者: 苏小脉    时间: 2010-11-28 14:02
回复 赛露休斯 的帖子

工程上右键 - 属性 - 配置属性 - 通用 - 字符集 - 设置为不使用字符集。
要么就把所有双引号字符串加上 TEXT(),如  TEXT("Loop loop and loop ...")
作者: 赛露休斯    时间: 2010-11-28 14:51
本帖最后由 赛露休斯 于 2010-11-28 14:54 编辑

回复 苏小脉 的帖子

设置了字符集以后运行出现另一个错误
error C4716: “abort_async_api”: 必须返回一个值
是在第16行发生的
作者: 苏小脉    时间: 2010-11-28 16:02
本帖最后由 苏小脉 于 2010-11-28 16:05 编辑

回复 赛露休斯 的帖子

把 HANDLE WINAPI abort_async_api() 改为 void WINAPI abort_async_api()

这是我写错了,不过由于是编译为 C 代码所以没发现

顺便改一下这个:工程右键属性 - C/C++ - 高级 - 编译为 - C 代码,否则开头两行指定的链接器选项会有问题。
作者: 赛露休斯    时间: 2010-11-29 03:14
dll创建成功了,然后测试的时候我把RUBY部分的 sleep 5 换成那个会卡机的API,不知道这样用对不对,它一遍又一遍的弹出"Loop loop and loop ...",没有下文了,未见中止。
另外我这个API在不同环境下可能有无法运行卡死的情况,所以我想如果该API在3秒内没有执行完毕则中止这个API,然后继续执行后面的代码。


作者: 苏小脉    时间: 2010-11-29 03:48
回复 赛露休斯 的帖子

……:L

DLL 的 thread_proc 函数里是放“那个会卡机的 API”的地方,我给你的例子代码是一个例子,你不改它就会一直循环弹对话框。Ruby 部分做的是计时,在 5 秒后停止无限弹对话框的线程。
作者: 赛露休斯    时间: 2010-11-29 13:37
回复 苏小脉 的帖子

C++的代码完全看不懂,能不能举个例子,比如这帖5楼的代码
http://rpg.blue/thread-162156-1-3.html
它是在RUBY中调用的,怎么放进thread_proc函数?
作者: 苏小脉    时间: 2010-11-29 14:42
回复 赛露休斯 的帖子

强调一下,这是 C 不是 C++。Ruby 调用的拿到 C 里写的更少:
  1. DWORD WINAPI thread_proc(void* param) {
  2.         return WAIT_FAILED != WaitForSingleObject(CreateEvent(NULL, 0, 0, NULL), INFINITE);
  3. }
复制代码





欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1