【问题标题】:pthread cancellation activation timepthread取消激活时间
【发布时间】:2012-04-03 00:26:31
【问题描述】:

我想在进程反初始化完成之前取消一个线程,如下所示。

rc2 = pthread_attr_init(&attr);
ERR_IF( rc2 != 0 );

rc2 = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ERR_IF( rc2 != 0 );

rc2 = pthread_create(&destroy_thread, &attr, destroy_expired_sessions, NULL);
ERR_IF( rc2 != 0 );
...
rc2 = pthread_cancel(destroy_thread);
ERR_IF( rc2 != 0 );

usleep(10); // without the sleep here, the real cancellation will be postponed.

rc2 = authSessionListDeInit();
ERR_IF( rc2 != 0 );

...

static void *destroy_expired_sessions(void *t)
{
    int rc2 = 0;

    (void)t;

    pthread_cleanup_push(cleanup_handler, NULL);

    rc2 = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (rc2 != 0)
        AUTH_DEBUG5("pthread_setcancelstate(): rc2 == %d\n", rc2);

    rc2 = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    if (rc2 != 0)
        AUTH_DEBUG5("pthread_setcanceltype(): rc2 == %d\n", rc2);

    ... // real work of the thread is done here
}

问题是,虽然这里设置了 PTHREAD_CANCEL_ASYNCHRONOUS,但真正的线程取消总是发生在 authSessionListDeInit() 之后,除非我在两者之间强制使用 usleep()。

我的理解是取消应该在通过 pthread_cancel() 发送取消请求之后立即发生,不是吗?

如果我的理解不正确,如何确保线程在调用 authSessionListDeInit() 之前被取消?

【问题讨论】:

    标签: c pthreads


    【解决方案1】:

    不,取消发生在cancellation points,例如。系统调用、libc 调用 - 查看函数的文档(例如 accept()close())或者你可以查看 here

    【讨论】:

    • 如果PTHREAD_CANCEL_DEFERRED设置为取消类型,你说的是真的,但是这里我将类型设置为PTHREAD_CANCEL_ASYNCHRONOUS,也就是说线程可以随时取消(一般情况下会取消)收到取消请求后立即,但系统不保证这一点)。
    【解决方案2】:

    来自docs

    目标线程中的取消处理应运行 相对于从返回的调用线程异步 pthread_cancel()。

    所以 pthread_cancel 可以在取消之前返回,这意味着你的假设是错误的。

    您可以考虑使用取消标志和/或条件变量在函数实际结束时发出信号,而不是使用 pthread_cancel。

    【讨论】:

    • 或者您可以在调用pthread_cancel 后等待同步对象(如信号量),并在完成清理以退出时取消线程信号(例如发布信号量)。
    • 你需要某种同步对象,而信号量是等待/信号语义最简单/最低的开销。唯一的另一个远程简单的解决方案是让线程拥有一个它持有的“终身互斥锁”并尝试锁定它以等待它退出,但是如果线程还没有足够远地进入它的启动函数,那么它就有一个竞争条件在您尝试取消互斥锁时锁定它。信号量在这里更好,因为它们没有所有者,因此您可以在创建线程之前将 sem 值初始化为 0。
    • 条件变量在这里也是一个可行的选择。与 R 的其他 cmets(我同意)一起,信号量在 pthread 中的重量较轻,但这似乎与您正在做的事情无关(假设此 deinit 代码不是循环代码)您可以看到这个 SO question有关信号量与 condvars 的讨论:stackoverflow.com/questions/70773/…
    • @QiangXu:创建一个正在执行任务但无法同步其结果的线程几乎总是无用的。顺便说一句,如果线程没有分离并且还没有人试图加入它,另一种解决方案是在pthread_cancel之后调用pthread_join...
    • Joinable 是默认值;您只需要分离的特殊属性。当你确实想要分离时,通常在 start 函数中写 pthread_detach(pthread_self()); 而不是只为分离标志创建一个属性更容易。
    猜你喜欢
    • 1970-01-01
    • 2012-09-12
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 2017-04-02
    • 2014-05-06
    • 1970-01-01
    相关资源
    最近更新 更多