我目前正在学习C和POSIXAPI,特别是p线程.我遇到了以下情况,这让我很惊讶,似乎事情不应该是这样的. 线程内的sleep调用正被来自主线程的取消请求中断,尽管该线程中的取消状态设置为禁用.

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>

static void *thread(void *arg)
{
    int oldstate;

    printf("other thread: started\n");

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
    printf("other thread: started doing thing that can't be canceled\n");

    errno = 0;
    sleep(10);
    if (errno)
        perror("sleep");

    printf("other thread: finished doing thing that can't be canceled\n");
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);

    printf("other thread: exiting\n");

    return NULL;
}

int main(void)
{
    pthread_t thr;
    void *res;

    pthread_create(&thr, NULL, thread, NULL);
    printf("main: created other thread\n");

    printf("main: letting other thread work for 3 seconds...\n");
    sleep(3);
    printf("main: canceling other thread\n");
    pthread_cancel(thr);

    printf("main: joining with other thread\n");
    res = NULL;
    pthread_join(thr, &res);
    if (res == PTHREAD_CANCELED)
        printf("main: canceled other thread\n");
    else
        printf("main: other thread result: %p\n", res);

    printf("main: exiting\n");

    return 0;
}

我预期该程序的输出如下:

main: created other thread
main: letting other thread work for 3 seconds...
other thread: started
other thread: started doing thing that can't be canceled
main: canceling other thread
main: joining with other thread
other thread: finished doing thing that can't be canceled
other thread: exiting
main: canceled other thread
main: exiting

但是,sleep被中断,输出如下:

main: created other thread
main: letting other thread work for 3 seconds...
other thread: started
other thread: started doing thing that can't be canceled
main: canceling other thread
main: joining with other thread
sleep: Interrupted system call
other thread: finished doing thing that can't be canceled
other thread: exiting
main: canceled other thread
main: exiting

这似乎是不对的.取消请求不是信号,对吗?那为什么会导致sleep中断呢?我预计代码会执行,就好像只有sleep(10)个代码,而不是以下代码:

// before `thread`:
static pthread_mutex_t sleep_mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t sleep_cv = PTHREAD_COND_INITIALIZER;

static void *sleep_thread(void *arg)
{
    int sleep_for = *((int *) arg);

    sleep(sleep_for);
    pthread_cond_broadcast(&sleep_cv);

    return NULL;
}

static void *thread(void *arg)
{
    // ...
    // instead of `sleep`:
    pthread_mutex_lock(&sleep_mut);
    pthread_t sleep_thr;
    int sleep_for = 10;
    pthread_create(&sleep_thr, NULL, sleep_thread, &sleep_for);
    pthread_cond_wait(&sleep_cv, &sleep_mut);
    pthread_mutex_unlock(&sleep_mut);
    // ...
}

推荐答案

正如我在 comments 中指出的那样,Linux实际上确实使用信号实现了取消.这就解释了一切.

C++相关问答推荐

C中空终止符后面的数字?

在函数中使用复合文字来初始化C语言中的变量

增加getaddrinfo返回的IP地址数量

进程在写入管道时挂起

&;(str[i])和(&;str)[i]有什么区别?

S的这种管道实施有什么问题吗?

这个计算C中阶乘的函数正确吗?

如何使用_newindex数组我总是得到错误的参数

处理EPOLL_WAIT中的接收数据和连接关闭信号

GCC奇怪的行为,有fork 和印花,有换行符和不换行符

我在反转双向链表时遇到问题

当内存来自Malloc时,将char*转换为另一个指针类型是否违反了严格的别名规则?

按长度对argv中的单词进行排序

不同原型的危险C函数是可能的

生产者消费者计数器意外输出的C代码

用C++初始化局部数组变量

Dlsym()的手册页解决方法仍然容易出错?

函数的typedef是标准 C 语法吗?它与函数指针的typedef有何不同?

可以从指针数组中的值初始化指针吗?

使用 SDL2 的 C 程序中的内存泄漏