How to stop a thread created with dispatch_async?

守給你的承諾、 提交于 2019-12-11 13:18:48

问题


I want to forcibly stop the thread created by dispatch_async if its in use for too much time, for example pass over 5 minutes. By searching over the internet, I got some one thought there was no way to stop the thread, does any one know that?

In my imagine, I want to create a NSTimer to stop the thread when time specified passed.

+ (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];

    });
} 

My runLuaScript method:

+ (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);
}

Dear @Martin R, should I use lstop like that, and when I want to stop the thread, just call stopLuaRunning method?

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

回答1:


You cannot kill a running block. You have to implement runLuaFile in a way that it works asynchronously and can be cancelled.

For example if running the script is done via NSTask, you can use terminate to kill the task if it is running too long.

NSOperation will probably not help because cancel relies on the operation to be "cooperative": the operation has to check regularly if it has been cancelled. That will not stop the running runLuaFile method.

UPDATE: From inspecting the source code "lua.c" of the Lua interpreter, it seems to me that you can cancel a running script using lua_sethook.

A very simple implementation (using a static variable for the Lua state) would be:

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);
}

A more elegant solution would use store the Lua state in an instance variable of the class and make runLuaFile and stopLuaRunning instance methods instead of class methods.




回答2:


You should use NSOperation and NSOperationQueue as they have built in support for cancellation so your operation can check if it's cancelled and your timer just calls cancel on the operation.




回答3:


By searching over the internet, I got some one though there was no way to stop the thread, does any one know that?

Don't bother; It's not yours to stop. If you have a reference to a queue, then you can call dispatch_release and it will be destroyed at the appropriate time, but you would not do this with the global queue.

Killing that thread would just kill a thread in the queue's pool and should be considered as good as undefined behavior.

If you want to control a thread's lifetime, create your own thread and interact with its run loop. But do ensure your programs return from their implementations normally -- don't just kill stuff because it isn't working for you or never returning. Martin R mentioned how this would happen -- your task should support timeout, cancellation, or another means to stop itself in the event the task has gone rogue.

Wain's also mentioned a good middle ground.




回答4:


Use NSOperation and NSOperationQueue.

Here is a long, but helpful guide.

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

The key point for you in this case, is there example of overriding 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

Notice the if (self.isCancelled) in the middle of the loop.

This is the "modern" iOS way of managing background operations without creating your own threads and managing them directly.



来源:https://stackoverflow.com/questions/17671828/how-to-stop-a-thread-created-with-dispatch-async

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!