1

如果线程使用时间过长,我想强制停止创建的线程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

4 回答 4

3

您应该使用NSOperationandNSOperationQueue因为它们内置了对取消的支持,因此您的操作可以检查它是否被取消,并且您的计时器只是调用cancel操作。

于 2013-07-16T08:42:34.607 回答
3

你不能杀死一个跑步者。您必须以runLuaFile一种异步工作且可以取消的方式实现。

例如,如果运行脚本是通过 完成的,如果任务运行时间过长NSTask,您可以使用它来终止任务。terminate

NSOperation可能无济于事,因为cancel依赖于“合作”操作:操作必须定期检查它是否已被取消。这不会停止运行runLuaFile方法。

更新:通过检查 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 状态存储在类的实例变量中,并使用 makerunLuaFilestopLuaRunning实例方法而不是类方法。

于 2013-07-16T09:41:06.267 回答
0

通过互联网搜索,我得到了一些,但没有办法停止线程,有人知道吗?

不要打扰;停下来不是你的事。如果您有对队列的引用,那么您可以调用dispatch_release它,它将在适当的时间销毁,但您不会对全局队列执行此操作。

杀死该线程只会杀死队列池中的一个线程,并且应该被视为与未定义的行为一样好。

如果要控制线程的生命周期,请创建自己的线程并与其运行循环交互。但是一定要确保你的程序从它们的实现中正常返回——不要仅仅因为它对你不起作用或永远不会返回而杀死东西。Martin R 提到了这种情况是如何发生的——你的任务应该支持超时、取消或其他在任务失控的情况下自行停止的方法。

韦恩还提到了一个很好的中间立场。

于 2013-07-16T09:24:26.030 回答
0

使用 NSOperation 和 NSOperationQueue。

这是一个很长但很有帮助的指南。

http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues

在这种情况下,您的关键点是覆盖 main 的示例。

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

于 2013-07-16T12:36:33.373 回答