как дочерний поток POSIX отменяется - PullRequest
5 голосов
/ 10 июля 2011
// 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 в основном потоке.

Вопрос>

По сути, мне нужно понять, как дочерний поток можно отменить в цикле, не проверяя сами флаги.

Также, пожалуйста, исправьте мое описание, если что-то не так.

Ответы [ 2 ]

6 голосов
/ 10 июля 2011

Происходит следующее: ваш цикл содержит хотя бы одну точку отмены, 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, и обработчик сигнала запускается, определяет, что он находится в середине отменяемой операции, и действует на запрос отмены.

3 голосов
/ 10 июля 2011

Пожалуйста, прочитайте сначала pthread_cancel справочную страницу. Это многое объясняет. Специально для вашего вопроса, внутри цикла не должно быть оператора проверки. Я не проверял реализацию Linux, но рациональным решением было бы отправить потоку сигнал, запрашивающий поток остановить / отменить. Если в потоке обработчика сигнала определено состояние, которое нельзя отменить, запрос помещается в очередь. Когда вы вызываете любую функцию, которая является точкой отмены , и новое состояние определяется как отменяемое, эта очередь проверяется, и если в очереди обнаруживается запрос на отмену, поток отменяется. По сути, неотменяемое состояние - это критическая секция . В вашем случае все ваши темы отменяются при вызове sleep (), так как это точка отмены. См. pthreads (7) .

...