【问题标题】:how the child POSIX thread is canceled如何取消子 POSIX 线程
【发布时间】:2011-10-02 07:04:17
【问题描述】:
// 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);
}

输出如下:

$ ./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...
$

等待3秒后,主线程发出命令pthread_cancel停止子线程,调用pthread_join命令后子线程真正开始响应取消。

此时主线程运行到pthread_join之后的那一行,子线程在下面代码的循环内运行,

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

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

问题>

基本上,我需要了解如何在不检查任何标志的情况下在循环内取消子线程。

另外,如果有任何错误,请更正我的描述。

【问题讨论】:

    标签: c linux multithreading pthreads


    【解决方案1】:

    发生的情况是,您的循环至少包含一个取消点 sleep(可能还有两个,因为 printf 是一个可选的取消点)。

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

    if (thread_local_cancellation_flag) {
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE);
        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED);
        pthread_exit(PTHREAD_CANCELED);
    }
    

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

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

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

    【讨论】:

      【解决方案2】:

      请先阅读pthread_cancel 手册页。它解释了很多。具体到您的问题,循环内不应有检查语句。我还没有检查过 Linux 的实现,但这样做的合理做法是向线程发送一个信号,请求线程停止/取消。如果信号处理线程中的线程被确定为无法取消的状态,则请求排队。一旦您调用任何 cancellation point 函数并且确定新状态是可取消的,就会检查该队列,如果在队列中找到取消请求 - 线程将被取消。基本上,不可取消状态是critical section。在您的情况下,调用sleep () 时,您的所有线程都被取消,因为这是一个取消点。见pthreads (7)

      【讨论】:

      • pthread_setcanceltypepthread_setcancelstate 不是取消点。取消状态只在取消点检查,除非取消类型是异步的,在这种情况下它可以在其他点检查并异步中断代码(但不是必需的)。
      猜你喜欢
      • 2013-10-23
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      相关资源
      最近更新 更多