Pthreads pthread_exit(pthread_cancelled)和pthread_cancel(pthread_self())之间的区别

Pthreads pthread_exit(pthread_cancelled)和pthread_cancel(pthread_self())之间的区别,pthreads,signals,Pthreads,Signals,调用pthread\u exit(pthread\u cancelled)时,我有预期的行为(堆栈展开、析构函数调用),但调用pthread\u cancel(pthread\u self())只是终止了线程 为什么pthread\u exit(pthread\u cancelled)和pthread\u cancel(pthread\u self())有显著差异,并且在后一种情况下不会释放线程内存 背景如下: 调用是从信号处理程序发出的,这种奇怪方法背后的原因是取消一个线程,等待外部库semo

调用
pthread\u exit(pthread\u cancelled)
时,我有预期的行为(堆栈展开、析构函数调用),但调用
pthread\u cancel(pthread\u self())
只是终止了线程

为什么
pthread\u exit(pthread\u cancelled)
pthread\u cancel(pthread\u self())
有显著差异,并且在后一种情况下不会释放线程内存

背景如下:

调用是从信号处理程序发出的,这种奇怪方法背后的原因是取消一个线程,等待外部库
semop()
完成(我想是在
EINTR
上循环)

我注意到,从其他线程调用
pthread\u cancel
不起作用(好像
semop
不是取消点),但向线程发送信号,然后调用
pthread\u exit
起作用,但在信号处理程序中调用析构函数。
pthread\u cancel
可能会将操作推迟到下一个取消点。

就特定于线程的清理行为而言,通过
pthread\u cancel()
取消线程与通过
pthread\u exit()
退出线程之间应该没有区别

:

[…]执行取消操作时,应调用线程的取消清理处理程序。当最后一个取消清理处理程序返回时,应为线程调用特定于线程的数据析构函数。当最后一个析构函数返回时,线程将终止


来自Linux的:

对请求的取消执行操作时,线程将执行以下步骤(按此顺序):

  • 取消清理处理程序弹出(与推送顺序相反)并调用。(请参阅pthread_cleanup_push(3)。)

  • 以未指定的顺序调用特定于线程的数据析构函数。(请参阅pthread\u key\u create(3)。)

  • 线程终止。(请参阅pthread_exit(3)。)


  • 关于通过发送线程来引入取消点的策略,我怀疑这是最干净的方法

    由于许多系统调用在将
    errno
    设置为
    EINTR
    时接收到信号时返回,因此很容易捕捉到这种情况,只需通过
    pthread\u exit()
    在这种情况下让线程干净地结束

    一些伪代码:

    while (some condition) 
    {
      if (-1 == semop(...))
      { /* getting here on error or signal reception */
        if (EINTR == errno)
        { /* getting here on signal reception */
          pthread_exit(...);
        }
      }
    }
    

    就特定于线程的清理行为而言,通过
    pthread\u cancel()
    取消线程和通过
    pthread\u exit()
    退出线程之间应该没有区别

    :

    […]执行取消操作时,应调用线程的取消清理处理程序。当最后一个取消清理处理程序返回时,应为线程调用特定于线程的数据析构函数。当最后一个析构函数返回时,线程将终止


    来自Linux的:

    对请求的取消执行操作时,线程将执行以下步骤(按此顺序):

  • 取消清理处理程序弹出(与推送顺序相反)并调用。(请参阅pthread_cleanup_push(3)。)

  • 以未指定的顺序调用特定于线程的数据析构函数。(请参阅pthread\u key\u create(3)。)

  • 线程终止。(请参阅pthread_exit(3)。)


  • 关于通过发送线程来引入取消点的策略,我怀疑这是最干净的方法

    由于许多系统调用在将
    errno
    设置为
    EINTR
    时接收到信号时返回,因此很容易捕捉到这种情况,只需通过
    pthread\u exit()
    在这种情况下让线程干净地结束

    一些伪代码:

    while (some condition) 
    {
      if (-1 == semop(...))
      { /* getting here on error or signal reception */
        if (EINTR == errno)
        { /* getting here on signal reception */
          pthread_exit(...);
        }
      }
    }
    

    结果证明没有区别。 然而,一些有趣的副作用发生了

    对std::iostream尤其是cerr/cout的操作包括取消点。当基础操作被取消时,流被标记为不好。因此,如果只有一个线程在尝试打印时发现取消,您将不会从任何其他线程获得任何输出

    因此,可以使用
    pthread\u setcancelstate()
    pthread\u testcancel()
    或者在需要时调用
    cerr.clear()


    仅适用于C++流,STDRR,STDIN似乎不受影响。 然而,一些有趣的副作用发生了

    对std::iostream尤其是cerr/cout的操作包括取消点。当基础操作被取消时,流被标记为不好。因此,如果只有一个线程在尝试打印时发现取消,您将不会从任何其他线程获得任何输出

    因此,可以使用
    pthread\u setcancelstate()
    pthread\u testcancel()
    或者在需要时调用
    cerr.clear()


    仅适用于C++流,STDRR,STDIN似乎不受影响。

    < P>首先,有两个与线程相关的东西,它将告诉您调用pthRead Sql()时要做什么。

    第一个函数将告诉您是否可以取消该线程,第二个函数将告诉您何时以及如何取消该线程,例如,该线程是在您发送取消请求后立即终止,还是需要等到该线程达到某个里程碑后才终止

    调用pthread_cancel()时,线程不会直接终止,将执行上述两个操作,即检查该线程是否可以取消,如果可以,何时取消

    如果禁用取消状态,则pthread_cancel()无法终止该线程,但取消请求将停留在队列中,等待该线程变为可取消状态,即,如果