PTHREAD_CLEANUP_PUSH - Linux手册页

时间:2019-08-20 18:01:02  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-06-09

名称

pthread_cleanup_push,pthread_cleanup_pop-推入和弹出线程取消清理处理程序

语法

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *),
                          void *arg);
void pthread_cleanup_pop(int execute);

Compile and link with -pthread.

说明

这些函数操纵调用线程的线程取消清除处理程序的堆栈。清除处理程序是在取消线程时(或在以下所述的各种其他情况下)自动执行的功能;例如,它可能会解锁互斥锁,以便该互斥锁可用于进程中的其他线程。

pthread_cleanup_push()函数将例程推入清理处理程序堆栈的顶部。当例程在以后被调用时,它将被赋予arg作为其参数。

pthread_cleanup_pop()函数会删除清理处理程序堆栈顶部的例程,如果execute非零,则可以选择执行该例程。

在以下情况下,取消清除处理程序将从堆栈中弹出并执行:

1.
取消线程后,将弹出所有堆叠的清理处理程序并以与将它们推入堆栈的顺序相反的顺序执行。
2.
当线程通过调用pthread_exit(3)终止时,所有清理处理程序均按照上一点所述的方式执行。 (如果线程通过从线程启动函数执行返回而终止,则不会调用清理处理程序。)
3.
当线程使用非零执行参数调用pthread_cleanup_pop()时,将弹出并执行最顶层的清除处理程序。

POSIX.1允许将pthread_cleanup_push()和pthread_cleanup_pop()实现为宏,这些宏分别扩展为包含aq {aq和aq} aq的文本。因此,调用者必须确保对这些函数的调用在同一函数内且在相同的词汇嵌套级别上配对。 (换句话说,仅在执行指定的代码段期间才建立清理处理程序。)

如果自跳转缓冲区由setjmp(3)(sigsetjmp(3)填充以来,如果对pthread_cleanup_push()或pthread_cleanup_pop()进行了任何调用而没有该对的匹配调用,则调用longjmp(3)(siglongjmp(3))会产生不确定的结果))。同样,从清理处理程序内部调用longjmp(3)(siglongjmp(3))会产生不确定的结果,除非跳转缓冲区也由处理程序内部的setjmp(3)(sigsetjmp(3))填充。

返回值

这些函数不返回值。

错误说明

没有错误。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
pthread_cleanup_push(),pthread_cleanup_pop()Thread safetyMT-Safe

遵循规范

POSIX.1-2001,POSIX.1-2008。

备注

在Linux上,pthread_cleanup_push()和pthread_cleanup_pop()函数被实现为宏,这些宏分别扩展为包含aq {aq和aq} aq的文本。这意味着在对这些函数的成对调用范围内声明的变量仅在该范围内可见。

POSIX.1说,使用returnbreak,continue或goto来过早离开一个放在方括号pthread_cleanup_push()和pthread_cleanup_pop()内的块的效果是不确定的。便携式应用程序应避免这样做。

示例

以下程序提供了使用此页面中描述的功能的简单示例。该程序创建一个线程,该线程执行由pthread_cleanup_push()和pthread_cleanup_pop()括起来的循环。此循环每秒增加一次全局变量cnt。根据提供的命令行参数,主线程向另一个线程发送取消请求,或设置一个全局变量,该全局变量导致另一个线程退出其循环并正常终止(通过执行返回)。

在以下Shell会话中,主线程向另一个线程发送取消请求:

$ ./a.out
New thread started
cnt = 0
cnt = 1
Canceling thread
Called clean-up handler
Thread was canceled; cnt = 0

从上面可以看到,该线程已被取消,并且取消取消处理程序已被调用,并将全局变量cnt的值重置为0。

在下一次运行中,主程序设置一个全局变量,该变量导致其他线程正常终止:

$ ./a.out x
New thread started
cnt = 0
cnt = 1
Thread terminated normally; cnt = 2

从上面可以看到,清理处理程序未执行(因为cleanup_pop_arg为0),因此cnt的值未重置。

在下一次运行中,主程序设置一个全局变量,该变量导致另一个线程正常终止,并为cleanup_pop_arg提供一个非零值:

$ ./a.out x 1
New thread started
cnt = 0
cnt = 1
Called clean-up handler
Thread terminated normally; cnt = 0

在上面的代码中,我们看到尽管未取消线程,但清理处理程序仍被执行,因为赋予pthread_cleanup_pop()的参数非零。

Program source

#include <pthread.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static int done = 0;
static int cleanup_pop_arg = 0;
static int cnt = 0;

static void
cleanup_handler(void *arg)
{
    printf("Called clean-up handler\n");
    cnt = 0;
}

static void *
thread_start(void *arg)
{
    time_t start, curr;

    printf("New thread started\n");

    pthread_cleanup_push(cleanup_handler, NULL);

    curr = start = time(NULL);

    while (!done) {
        pthread_testcancel();           /* A cancellation point */
        if (curr < time(NULL)) {
            curr = time(NULL);
            printf("cnt = %d\n", cnt);  /* A cancellation point */
            cnt++;
        }
    }

    pthread_cleanup_pop(cleanup_pop_arg);
    return NULL;
}

int
main(int argc, char *argv[])
{
    pthread_t thr;
    int s;
    void *res;

    s = pthread_create(&thr, NULL, thread_start, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    sleep(2);           /* Allow new thread to run a while */

    if (argc > 1) {
        if (argc > 2)
            cleanup_pop_arg = atoi(argv[2]);
        done = 1;

    } else {
        printf("Canceling thread\n");
        s = pthread_cancel(thr);
        if (s != 0)
            handle_error_en(s, "pthread_cancel");
    }

    s = pthread_join(thr, &res);
    if (s != 0)
        handle_error_en(s, "pthread_join");

    if (res == PTHREAD_CANCELED)
        printf("Thread was canceled; cnt = %d\n", cnt);
    else
        printf("Thread terminated normally; cnt = %d\n", cnt);
    exit(EXIT_SUCCESS);
}

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/