如何停止使用dispatch_async创建的线程?

时间:2013-07-16 08:40:40

标签: ios objective-c multithreading nstimer

我想强行停止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!");
}

4 个答案:

答案 0 :(得分:3)

您应该使用NSOperationNSOperationQueue,因为它们已经内置支持取消,因此您的操作可以检查它是否已取消,而您的计时器只是在操作上调用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状态存储在类的实例变量中 并使runLuaFilestopLuaRunning实例方法而不是类方法。

答案 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方式,无需创建自己的线程并直接管理它们。