随笔-90  评论-947  文章-0  trackbacks-0

如题。

稍微解释下,因为有可能有人会误会:放新线程里面去不就可以了?这没有解决问题。如此的话,你那个线程函数怎么写?或者线程函数里调用的某个任务函数怎么写?总之,多线程虽然总是出现在这些问题的解决方案中,但不是多线程解决了这个问题。嗯……不知道说清楚了没?

目前我心里的答案只有这一种模式:

bool DoTask(HANDLE hQuitSignal)
{
    while (!QuitCondition)
    {
        if (WaitForSingleObject(hQuitSignal, 0) == WAIT_OBJECT_0)
        {
            return false;
        }

        // Do something
    }

    return true;
}

其中,“// Do something”部分要细化到瞬间执行完成的细度。

但是我很困惑的是,如果这些任务很繁重,难道我必须每进行一些操作就 if (WaitForSingleObject(hQuitSignal, 0) == WAIT_OBJECT_0) 检查下吗?这样岂不是这种检测代码充斥在任务中了?

不知各位有何经验和体会,求教~

posted on 2011-05-26 00:36 溪流 阅读(2834) 评论(29)  编辑 收藏 引用 所属分类: C++Windows

评论:
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 01:10 | Linuxer
嗯,我也有类似的问题。

脚本是阻塞的比较方便,但是阻塞脚本又需要即时的响应退出消息,没有想到很好的解决办法,搭车求解  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 01:31 | OwnWaterloo
SetThreadContext/GetThreadContext?
在其他线程上执行 setjmp/longjmp... 太有意思了……
setjmp 到 longjmp 之间的C++代码全得重写…… 哇……
  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 01:35 | tfzxyinhao
异步函数该怎么实现呢,新开个线程然后返回吗?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 02:26 | OwnWaterloo
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

DWORD CALLBACK infinite(void* arg) { for (;;) Sleep(0); return 0; }
void cancel(void) { ExitThread(12); }

int main(void)
{

DWORD tid = 0;
HANDLE thread = CreateThread(NULL, 0, infinite, 0, 0, &tid);
CONTEXT ctx = {0};
ctx.ContextFlags = CONTEXT_ALL;
SuspendThread(thread);
GetThreadContext(thread, &ctx);
ctx.Eip = (DWORD)cancel;
SetThreadContext(thread, &ctx);
ResumeThread(thread);
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, &tid);
CloseHandle(thread);
return (int)tid;

}
  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 09:25 | shaker(太子)
可以用APC 不过没试过  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 10:46 | vincent
我觉得你这样写挺好
做等能把轮询变被动的方案  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 12:36 | 天堂的隔壁
个人认为要看你的任务究竟在干什么,消耗CPU还是等待消息(网络,其他线程等)。

如果是前者,把这段计算局部化(否则会对其他线程的状态造成影响,会很难处理),然后想退出的时候把线程干掉就好了。

如果是后者,类似你的方法;select加上超时后检查退出状态(这样不会马上退出,但退出等待时间也一般是可以接受的)等应该都是可以接受的。  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 12:36 | yrj
暴力一点的办法:繁重任务只管执行,没有退出代码。谁想让这个任务退出,谁就强行终止这个任务。资源释放问题,可以用新进程执行这个任务的办法解决。  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:23 | 溪流
@天堂的隔壁
@yrj
我发这篇文章,说这么多,就是为了不使用暴力手段。不然怎么知道线程究竟在哪儿被结束的?只有天知道了  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:25 | 溪流
@OwnWaterloo
还是同样的问题啊,在执行 ctx.Eip = (DWORD)cancel; 的时候,原始的代码执行到哪一步了呢?当下是否适合跳到别处呢?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:27 | 溪流
@tfzxyinhao
我觉得是的
  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:28 | 溪流
@shaker(太子)
APC 是啥?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:43 | 放屁阿狗
任何函数代码执行都是靠系统kernel进行调度的,而最理想的退出方式就是接收来自系统的signal来中断代码,信号灯、事件、condition,select都是可以实现的  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 13:52 | 溪流
@放屁阿狗
不错。那么是不是只能像我一开始举例的那样子写任务代码呢?任务代码里要充斥着退出条件检测?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 15:38 | OwnWaterloo
@溪流
哦, 你还想要 "安全的退出点" 啊?
你想想这两种需求是否是矛盾的……
1. 只在一些点上可退出
2. 代码中在这些点上又不要显式写出测试
  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 15:44 | 溪流
@OwnWaterloo
好像有点矛盾的感觉。。。

但是,安全的退出点我觉得是必须的。比如我在写文件,过程虽然中断了但是我必须保证已写部分是符合格式的,还可能要写点结尾性质的数据;又比如我在更改一系列具有关联的状态数据,我必须保证这些数据的一致性,不能随便找个点退出;。。。是不是?

我想了解对于此类函数你们大家都是怎样写的?是否也跟我一样隔段代码检测一下隔段步骤再检测一下?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 17:48 | jejer
waitformultiobject
通过一个object来控制 想退出的时候set这个object即可  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 17:49 | jejer
对了 投递一个APC事件好像也可以  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 18:22 | vincent
@放屁阿狗
signal是王道
定义一个自己的signal好了

其他的更多是用于同步,其实不符合这个语意  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 21:36 | tom
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 22:15 | 杨粼波
用coroutine可以实现。  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢?[未登录] 2011-05-26 22:16 | 杨粼波
补充一下,在Windows下面可以用纤程。
是一种类似coroutine的实现。  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 23:21 | yrj
"安全的退出点" 和"随时立即退出"这两个要求矛盾。如果长时间任务能被拆分成 N 个状态,每个任务的执行时间满足你“随时立即”的时间要求,可用状态机解决这个问题。  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 23:42 | yrj
bool DoTask(HANDLE hQuitSignal)
{
int state = 0;

while (!QuitCondition)
{
if (WaitForSingleObject(hQuitSignal, 0) == WAIT_OBJECT_0)
{
DoQuit(state);
return false;
}

DoSomeThing(state);
++state;
}

return true;
}  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-26 23:58 | 溪流
@yrj
所以最后还是需要类似我开头写的那样子,是吗?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-27 00:49 | OwnWaterloo
@杨粼波
lz需要的应该是"被其他线程中止", 而不是"自主中止" —— 否则直接return不就完了?
coroutine 是自主切换的, COoperate。
  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-27 01:03 | OwnWaterloo
@溪流
另一种方式: 将那些退出测试点, 换成设置一个完成标记。

退出测试:
发出的中止请求会"延迟"到执行退出测试点时。
这个退出点之前的工作都是完成的, 余下的是放弃的。

完成标记:
发出的中止请求会"立即" —— 可能也会有一些延迟, 但至少不会等待到下一个完成标记 —— 执行。
上一个完成标记前的工作是完成的, 余下的是放弃的。

就看你的工作是否能分开了……
比如, 数据如果是行为单位, 就可以写一行后增加行计数。
行计数前的数据是有效的。
如果数据是, 比如xml, 那就完蛋……

  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2011-05-27 22:55 | 溪流
@OwnWaterloo
我觉得我的需求有点既要“被中止”又要“主动中止”的意思。。。事实上好像免不了在任务函数里插入检测语句或者如上面说的标记点。。。算了,,,应该就差不多那样子了。

另外,我突然觉得。一个“好”的程序,不,一个正确的程序。里面除了 WaitForSingleOnject(..., 0) 和 WaitForSingleOnject(..., INFINATE) 之外,是不应该出现 WaitForSingleOnject(..., 其他数值) 的,就像不应该出现 TerminateThread 一样。这看法合理否?  回复  更多评论
  
# re: 如何写 执行耗时任务的、可随时立即退出的函数 呢? 2012-03-26 15:29 | hoodlum1980
在耗时任务中需要频繁检测退出条件,这个是必然的罗。无法避免的。但检测一般可能是调用一个回调函数或者简单来说去读一个变量就可以了(要求比较低,甚至不需考虑线程同步),和耗时任务相比,这个检测的成本是比较低的。还有把任务的切分粒度,是要放在一个合适的度上,太细就会导致你说的检测过于频繁,显然是不好的,可能影响运行效率,太大的话会有延迟感。所以我觉得放在大约几十ms到200ms左右是比较合适的。耗时任务划分的单位粒度和任务有关,比如图像切片,写入读取,压缩和解压的数据块单位的大小。这个度必然是要自己去把握的。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理