我想强行停止dispatch_async
创建的线程,如果它在使用太长时间,例如超过5分钟。通过互联网搜索,我得到一个人认为没有办法阻止线程,有人知道吗?
在我的想象中,我想创建一个NSTimer
来在指定时间过去时停止线程。
+ (void)stopThread:(NSTimer*)timer
{
forcibly stop the thread???
}
+ (void)runScript:(NSString *)scriptFilePath
{
[NSTimer scheduledTimerWithTimeInterval:5*60 target:self selector:@selector(stopThread:) userInfo:nil repeats:NO];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[LuaBridge runLuaFile:scriptFilePath];
});
}
我的runLuaScript方法:
+ (void)runLuaFile:(NSString *)filePath
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int error2 = luaL_dofile(L, [filePath fileSystemRepresentation]);
if (error2) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
}
亲爱的@Martin R,我应该像这样使用lstop吗?当我想停止线程时,只需调用stopLuaRunning
方法?
static lua_State *L = NULL;
+ (void)runLuaFile:(NSString *)filePath
{
L = luaL_newstate();
luaL_openlibs(L);
int error2 = luaL_dofile(L, [filePath fileSystemRepresentation]);
if (error2) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
}
+ (void)stopLuaRunning:(lua_State *L)
{
lua_sethook(L, NULL, 0, 0);
luaL_error(L, "interrupted!");
}
答案 0 :(得分:3)
您应该使用NSOperation
和NSOperationQueue
,因为它们已经内置支持取消,因此您的操作可以检查它是否已取消,而您的计时器只是在操作上调用cancel
。
答案 1 :(得分:3)
你无法杀死正在运行的街区。您必须以异步工作的方式实现runLuaFile
,并且可以取消。
例如,如果通过NSTask
运行脚本,则可以使用terminate
来终止
任务是否运行太长。
NSOperation
可能无济于事,因为cancel
依赖于操作
“合作”:操作必须定期检查是否已被取消。那不会
停止正在运行的runLuaFile
方法。
UPDATE:从检查Lua解释器的源代码“lua.c”开始,它似乎
我可以使用lua_sethook
取消正在运行的脚本。
一个非常简单的实现(使用Lua状态的静态变量)将是:
static lua_State *L = NULL;
+ (void)runLuaFile:(NSString *)filePath
{
L = luaL_newstate();
luaL_openlibs(L);
int error2 = luaL_dofile(L, [filePath fileSystemRepresentation]);
if (error2) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
L = NULL;
}
static void lstop (lua_State *L, lua_Debug *ar)
{
lua_sethook(L, NULL, 0, 0);
luaL_error(L, "interrupted!");
}
+ (void)stopLuaRunning
{
if (L != NULL)
lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
更优雅的解决方案是使用将Lua状态存储在类的实例变量中
并使runLuaFile
和stopLuaRunning
实例方法而不是类方法。
答案 2 :(得分:0)
通过互联网搜索,虽然没有办法阻止该线程,但我得到了一个,是否有人知道?
不要打扰;这不是你的停止。如果您有对队列的引用,那么您可以调用dispatch_release
并在适当的时候销毁它,但是您不会对全局队列执行此操作。
杀死该线程只会杀死队列池中的一个线程,并且应该被视为未定义的行为。
如果要控制线程的生命周期,请创建自己的线程并与其运行循环进行交互。但是要确保你的程序正常地从他们的实现中返回 - 不要只是杀死东西,因为它不适合你或永远不会返回。 Martin R提到了这种情况会如何发生 - 你的任务应该支持超时,取消或其他手段,以便在任务变得流氓时自行停止。
Wain也提到了一个良好的中间立场。
答案 3 :(得分:0)
使用NSOperation和NSOperationQueue。
这是一篇很长但很有帮助的指南。
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
在这种情况下,你的关键点是覆盖主要的例子。
@interface MyLengthyOperation: NSOperation
@end
@implementation MyLengthyOperation
- (void)main {
// a lengthy operation
@autoreleasepool {
for (int i = 0 ; i < 10000 ; i++) {
// is this operation cancelled?
if (self.isCancelled)
break;
NSLog(@"%f", sqrt(i));
}
}
}
@end
注意循环中间的if(self.isCancelled)。
这是管理后台操作的“现代”iOS方式,无需创建自己的线程并直接管理它们。