Linux多线程3-3_线程取消

爷,独闯天下 提交于 2019-12-27 01:05:01

一、线程取消
将正在运行的线程取消执行,一个线程可以取消另一个线程,线程也可以自己取消自己。当线程被取消之后,会调用清理函数

二、取消函数
int pthread_cancel(pthread_t tid)
取消tid指定的线程,成功返回0。但是取消只是发送一个请求,并不意味着等待线程终止,而且发送成功也不意味着tid一定会终止

三、取消状态
1、概念
取消状态,就是线程对取消信号的处理方式,忽略或者响应。线程创建时默认响应取消信号
2、函数
int pthread_setcancelstate(int state, int *oldstate)
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。

四、取消类型
1、概念
取消类型,是线程对取消信号的响应方式,立即取消或者延时取消。线程创建时默认延时取消
2、函数
int pthread_setcanceltype(int type, int *oldtype)
设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。

五、取消点
取消一个线程,它通常需要被取消线程的配合。线程在很多时候会查看自己是否有取消请求。如果有就主动退出, 这些查看是否有取消的地方称为取消点很多地方都是包含取消点,包括:
pthread_join()、 pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()、write、read,大多数会阻塞的系统调用。你可以通过man pthreads来查看当前系统中那些操作是取消点

六、手册
PTHREAD_CANCEL(3) Linux Programmer’s Manual PTHREAD_CANCEL(3)
NAME
pthread_cancel - send a cancellation request to a thread
//向一个线程发送取消请求

SYNOPSIS
#include
//包含头文件pthread.h

​ int pthread_cancel(pthread_t thread);

​ Compile and link with -pthread.
​ //编译连接线程库

DESCRIPTION
The pthread_cancel() function sends a cancellation request to the thread thread. Whether and when the target thread reacts to the cancellation request depends on two attributes that are under the control of that thread: its cancelability state and type.
//这个函数是向目标线程发送一个取消请求,目标线程会如何处理取消请求或者何时去处理都由它自己的属性来决定,线程的取消属性有取消类型
//和取消状态

​ A thread’s cancelability state, determined by pthread_setcancelstate(3), can be enabled (the default for new threads) or disabled. If a thread has disabled cancellation, then a cancellation request remains queued until the thread enables cancellation. If a thread has enabled cancellation, then its cancelability type determines when cancellation occurs.
​ //线程的取消状态是由函数pthread_setcancelstate来设置的,可以设置为可取消(默认)或不可取消。如果是不可取消状态,那么取消请求会一直
​ //发送直到目标线程变为可取消状态。如果线程是一个可取消的状态,那么取消类型决定了何时被取消

A thread’s cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new threads). Asynchronous cancelability means that the thread can be canceled at any time (usually immediately, but the system does not guarantee this). Deferred cancelability means that cancellation will be delayed until the thread next calls a function that is a cancellation point. A list of functions that are or may be cancellation points is provided in pthreads(7).
//一线线程的取消类型有函数pthread_setcanceltype来修改,可以是异步的或者延时的(默认)。异步表示线程可以在任何时刻被取消(一般是立刻,
//但操作系统不会确保永远这样)。延时取消代表取消操作会被延时直到下一个取消点。关于那些函数是取消点,你可以看手册man pthreads

​ When a cancellation requested is acted on, the following steps occur for thread (in this order):
​ //一旦一个取消请求被响应了,那么以下的事情会发生

  1. Cancellation clean-up handlers are popped (in the reverse of the order in which they were pushed) and called. (See pthread_cleanup_push(3).)
    //一个已经压栈的清除操作会被调用

  2. Thread-specific data destructors are called, in an unspecified order. (See pthread_key_create(3).)
    //线程的特殊数据销毁程序会被调用,并且顺序不确定

    3. The thread is terminated.  (See pthread_exit(3).)
             //线程结束了
    

​ The above steps happen asynchronously with respect to the pthread_cancel() call; the return status of pthread_cancel() merely informs the caller whether the cancellation request was successfully queued.
​ //以上的操作都会异步的执行,pthread_cancel() 的返回值会表示到底取消有没有成功

​ After a canceled thread has terminated, a join with that thread using pthread_join(3) obtains PTHREAD_CANCELED as the thread’s exit status. (Joining with a thread is the only way to know that cancellation has completed.)
​ //如果一个线程因为被取消而结束,那么如果有线程用pthread_join去连接它,那么PTHREAD_CANCELED值会返回个这个join函数

RETURN VALUE

On success, pthread_cancel() returns 0; on error, it returns a non-zero error number.

//成功返回0,失败返回错误码

ERRORS
ESRCH No thread with the ID thread could be found.

//找不到指定的线程

CONFORMING TO
POSIX.1-2001

NOTES

​ On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32) is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is used.

//Linux的取消操作是用的信号的接口

PTHREAD_SETCANCELSTATE(3) Linux Programmer’s Manual PTHREAD_SETCANCELSTATE(3)
NAME
pthread_setcancelstate, pthread_setcanceltype - set cancelability state and type
//设置取消状态和类型

SYNOPSIS
#include
//包含头文件

​ int pthread_setcancelstate(int state, int *oldstate);
​ int pthread_setcanceltype(int type, int *oldtype);

​ Compile and link with -pthread.
​ //编译连接使用线程库

DESCRIPTION
The pthread_setcancelstate() sets the cancelability state of the calling thread to the value given in state. The previous cancelability state of the thread is returned in the buffer pointed to by oldstate. The state argument must have one of the following values:
//这个函数可以设置线程的取消状态,之前的取消状态会返回到oldstate指定的缓冲区,取消状态只能是下面的值

​ PTHREAD_CANCEL_ENABLE
​ The thread is cancelable. This is the default cancelability state in all new threads, including the initial thread. The thread’s cancelability type determines when a cancelable thread will respond to a cancellation request.
​ //这个线程是可以取消的。这是一个线程默认的状态,包含初始化。线程的取消类型决定了线程何时响应取消请求

PTHREAD_CANCEL_DISABLE
The thread is not cancelable. If a cancellation request is received, it is blocked until cancelability is enabled.
//这个线程是不可取消的。如果取消请求来了,它会阻塞,直到线程可以取消。

​ The pthread_setcanceltype() sets the cancelability type of the calling thread to the value given in type. The previous cancelability type of the thread is returned in the buffer pointed to by oldtype. The type argument must have one of the following values:
​ //pthread_setcanceltype用来设置线程的取消类型。之前的取消类型会返回到oldtype指向的缓冲区,取消类型只能是一下的值

​ PTHREAD_CANCEL_DEFERRED
​ A cancellation request is deferred until the thread next calls a function that is a cancellation point (see pthreads(7)). This is the default cancelability type in all new threads, including the initial thread.
​ //取消请求被延时了,直到下一个取消点。

PTHREAD_CANCEL_ASYNCHRONOUS

The thread can be canceled at any time. (Typically, it will be canceled immediately upon receiving a cancella- tion request, but the system doesn’t guarantee this.)
//线程可以在任何时刻被取消(一般是立刻,但操作系统不会确保永远这样)

The set-and-get operation performed by each of these functions is atomic with respect to other threads in the process calling the same function.
//这些set和get操作都是原子的

RETURN VALUE
On success, these functions return 0; on error, they return a non-zero error number.
//成功返回0,失败返回错误码

ERRORS
The pthread_setcancelstate() can fail with the following error:
//pthread_setcancelstate()会有以下错误码

​ EINVAL Invalid value for state.
​ //取消状态是无效的

​ The pthread_setcanceltype() can fail with the following error:
​ //pthread_setcanceltype()会有以下错误码

​ EINVAL Invalid value for type.
​ //取消类型是无效的

CONFORMING TO
POSIX.1-2001.

七、实例
1、程序框架

2、源代码

/*
 *int pthread_cancle(pthread_t tid)
 * 取消tid指定的线程,成功返回0。但是取消只是发送一个请求,
 * 并不意味着等待线程终止,而且发送成功也不意味着tid一定会终止
 *int pthread_setcancelstate(int state, int *oldstate) 
 * 设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)
 * 和PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信
 * 号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。
 *int pthread_setcanceltype(int type, int *oldtype) 
 *     设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和
 *     PTHREAD_CANCEL_ASYNCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号
 *     后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL
 *     则存入运来的取消动作类型值。
 */

#include "apue.h"

void *thread_fun(void *arg)
{
    int stateval;
    int typeval;
    stateval = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    if(stateval != 0)
    {
        printf("set cancel state failed\n");
    }
    printf("Im new thread\n");
    sleep(4);


    printf("about to cancel \n");
    stateval = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if(stateval != 0)
    {
        printf("set cancel state failed\n");
    }
    typeval = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    if(typeval != 0)
    {
        printf("set cancel type failed\n");
    }
    
    printf("first cancel point\n");
    printf("second cancel point\n");

    return (void *)20;
}

int main()
{
    pthread_t tid ;
    int err, cval, jval;
    void *rval;

    err = pthread_create(&tid, NULL, thread_fun, NULL);
    if(err != 0)
    {
        printf("create thread failed\n");
        return 0;
    }
    sleep(2);

    cval = pthread_cancel(tid);
    if(cval != 0)
    {
        printf("cancel thread failed\n");
    }
    jval = pthread_join(tid, &rval);
    
    printf("new thread exit code is %d\n", (int *)rval);

    return 0;
}

3、练习:证明线程可以自己取消自己

/*
 *DESCRIPTION: 一个新线程自己可以取消自己
 *    int pthread_cancel(pthread_t tid)
 *    取消tid指定的线程,成功返回0。但是取消只是发送一个请求,并不意味着等待线程终止,而且发送成功也不意味着tid一定会终止
 *    int pthread_setcancelstate(int state, int *oldstate) 
 *    设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
 *    int pthread_setcanceltype(int type, int *oldtype) 
 *    设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到
 *    信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
 */
#include "apue.h"

int err;
pthread_t tid;

void *thread_fun(void *arg)
{
    printf("I'm new thread\n");

    printf("I'm about to cancel myself\n");
    //设置取消类型为延时取消
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    //设置取消状态为可以取消
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    //取消自己
    err = pthread_cancel(pthread_self());
    if(err == 0)
    {
        printf("cancel myself success\n");
    }
    printf("cancel myself failed\n");
    
    pthread_exit((void *)0);
}


int main()
{
    //创造新线程
    err = pthread_create(&tid, NULL, thread_fun, NULL);
    if(err != 0)
    {
        printf("create new thread1 failed\n");
        return 0;
    }

    err = pthread_join(tid, NULL);
    if(err != 0)
    {
        printf("main thread join new thread failed\n");
    }
    else
    {
        printf("main thread join new thread success\n");
    }
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!