【问题标题】:How to stop a thread created with dispatch_async?如何停止使用 dispatch_async 创建的线程?
【发布时间】:2013-07-16 08:40:40
【问题描述】:

如果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!");
}

【问题讨论】:

  • LuaBridge 类从何而来?
  • 我的意思是:LuaBridge 不是标准的 Foundation 类。 是实现它还是它是一个第三方框架?
  • 所以问题是runLuaFile 运行时间过长?你不能杀死一个运行块(或 NSOperation)。您必须以异步工作且可以取消的方式实现runLuaFile
  • 为什么人们不赞成投票?该问题的尝试解决方案不正确,但我认为这是一个有效的问题。
  • @StephenDarlington:你说得对,这是一个有趣的问题。

标签: ios objective-c multithreading nstimer


【解决方案1】:

你不能杀死一个正在运行的方块。您必须以异步工作且可以取消的方式实现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 状态存储在类的实例变量中 并创建 runLuaFilestopLuaRunning 实例方法而不是类方法。

【讨论】:

  • [LuaBridge runLuaFile]方法会运行一个lua脚本,所以我很难检查超时并自行停止,因为我无法控制lua脚本中的逻辑。
  • @Bob:但是如何执行脚本呢?你用NSTask吗? (你能展示你的 LuaBrigde 实现吗?)
  • 楼上的runLuaScript方法的实现我已经加了,请看一下。
  • 我不使用NSTask,我使用lua c库来实现lua和c的交互。
  • @Bob:我对 Objective-C 有所了解,但不幸的是,对 Lua 几乎一无所知。如果luaL_dofile(或lua_pcall)不支持超时或取消方法,那么这将很困难。也许你可以在 Lua 论坛中询问如何做到这一点。
【解决方案2】:

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

【讨论】:

  • 但是如果runLuaFile: 方法运行时间过长,这不会停止。
  • @MartinR 为什么不添加您的解决方案(“您必须以异步工作且可以取消的方式实现 runLuaFile”)作为答案?这是正确的解决方案。
【解决方案3】:

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

别打扰;停下来不是你的事。如果你有一个队列的引用,那么你可以调用dispatch_release,它会在适当的时候被销毁,但你不会对全局队列这样做。

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

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

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

【讨论】:

  • [LuaBridge runLuaFile]方法会运行一个lua脚本,所以我很难检查超时并自行停止,您有什么想法吗?谢谢。
  • @Bob 抱歉,我不知道您的 Lua 实现如何支持终止正在运行的脚本。
  • 还是谢谢大家:)
【解决方案4】:

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

【讨论】:

  • 这已经在另一个答案中提出过,我也有同样的评论:如果runLuaFile: 方法运行时间过长,它不会停止它。
  • 知道了...正确。 runLuaFile 需要进一步分解以允许操作中断。也许图书馆不允许这样做。
  • 假设可以做到(请参阅我的回答中的“更新”),但尚未测试。
猜你喜欢
  • 1970-01-01
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 2010-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多