如何取消子POSIX线程

q09*_*987 5 c linux multithreading pthreads

// threadA.c
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    sleep(3);
    printf("Canceling thread...\n");
    res = pthread_cancel(a_thread);
    if (res != 0) {
        perror("Thread cancelation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    int i, res, j;
    res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (res != 0) {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    if (res != 0) {
        perror("Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf("thread_function is running\n");
    for(i = 0; i < 10; i++) {
        printf("Thread is still running (%d)...\n", i);
        sleep(1);
    }
    pthread_exit(0);
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

$ ./threadA
thread_function is running
Thread is still running (0)...
Thread is still running (1)...
Thread is still running (2)...
Canceling thread...
Waiting for thread to finish...
$
Run Code Online (Sandbox Code Playgroud)

完成等待3秒后,主线程发出命令pthread_cancel以停止子线程,并且在调用命令pthread_join之后,子线程确实开始响应取消.

此时,主线程在pthread_join之后立即运行到该行,子线程在以下代码的循环内运行,

    for(i = 0; i < 10; i++) {
        printf("Thread is still running (%d)...\n", i);
        sleep(1);
    }
Run Code Online (Sandbox Code Playgroud)

我在这个循环中没有看到任何检查语句,但主线程仍然可以取消子线程.我假设POSIX多线程系统内部有一个检查系统,以便在主线程中调用pthread_join时它可以终止子线程.

问>

基本上,我需要了解如何在循环内取消子线程而不检查任何标志.

另外,如果有任何问题,请更正我的描述.

R..*_*R.. 6

发生的事情是你的循环包含至少一个取消点,sleep(可能是两个,因为printf是一个可选的取消点).

作为取消点意味着该函数包含类似于以下的逻辑:

if (thread_local_cancellation_flag) {
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED);
    pthread_exit(PTHREAD_CANCELED);
}
Run Code Online (Sandbox Code Playgroud)

然而,实际上,它有点复杂,因为如果取消请求到达而函数正在"等待"或"阻塞"某些事件发生(如睡眠时间到期或从套接字输入),它必须采取行动.因此,需要某种异步传递机制,典型的实现是为此使用信号,但实际上很难做到正确,而流行的实现并不是那么好.对于其他实现可能共享的glibc中的一些丑陋角落,请参阅此错误报告:

http://sourceware.org/bugzilla/show_bug.cgi?id=12683

在您的情况下,几乎肯定会发生的是,当线程正在等待时sleep,取消请求到达(通过信号),并且信号处理程序运行,确定它处于可取消操作的中间,并对取消请求起作用.