C++ pthread_cond_timedwait()用于取消冗长任务的用法

C++ pthread_cond_timedwait()用于取消冗长任务的用法,c++,linux,multithreading,C++,Linux,Multithreading,我有一种情况,我想取消一个线程,如果它需要太多的时间来完成。为此,我使用了第二个线程,等待第一个线程完成,但不超过几秒钟。pthread_cond_timedwait()函数似乎非常适合我的使用场景,但它的行为似乎不像我预期的那样。更具体地说,尽管pthread_cond_timedwait()函数返回ETIMEDOUT,但它仅在本应取消的线程完成后才返回,这违背了整个目的 这是我的测试代码: #include <unistd.h> #include <stdl

我有一种情况,我想取消一个线程,如果它需要太多的时间来完成。为此,我使用了第二个线程,等待第一个线程完成,但不超过几秒钟。pthread_cond_timedwait()函数似乎非常适合我的使用场景,但它的行为似乎不像我预期的那样。更具体地说,尽管pthread_cond_timedwait()函数返回ETIMEDOUT,但它仅在本应取消的线程完成后才返回,这违背了整个目的

这是我的测试代码:

    #include <unistd.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <iostream>
    #include <cstring>

    #define WAIT_INTERVAL 5
    #define THREAD_SLEEP 10

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t condition = PTHREAD_COND_INITIALIZER;

    pthread_t t1;
    pthread_t t2;

    void* f1(void*);
    void* f2(void*);

    int main()
    {
        pthread_create(&t1, NULL, &f1, NULL);
        pthread_create(&t2, NULL, &f2, NULL);

        pthread_join(t1, NULL);
        pthread_join(t2, NULL);

        std::cout << "Thread(s) successfully finished" << std::endl << std::flush;

        exit(EXIT_SUCCESS);
    }

    void* f1(void*)
    {
        pthread_mutex_lock(&mutex);
        timespec ts = {0};
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_sec += WAIT_INTERVAL;
        std::cout << __FUNCTION__ << ": Waiting for at most " << WAIT_INTERVAL << " seconds starting now" << std::endl << std::flush;
        int waitResult = pthread_cond_timedwait(&condition, &mutex, &ts);
        if (waitResult == ETIMEDOUT)
        {
            std::cout << __FUNCTION__ << ": Timed out" << std::endl << std::flush;
            int cancelResult = pthread_cancel(t2);
            if (cancelResult)
            {
                std::cout << __FUNCTION__ << ": Could not cancel T2 : " << strerror(cancelResult) << std::endl << std::flush;
            }
            else
            {
                std::cout << __FUNCTION__ << ": Cancelled T2" << std::endl << std::flush;
            }
        }
        std::cout << __FUNCTION__ << ": Finished waiting with code " << waitResult << std::endl << std::flush;
        pthread_mutex_unlock(&mutex);
    }

    void* f2(void*)
    {
        pthread_mutex_lock(&mutex);
        std::cout << __FUNCTION__ << ": Started simulating lengthy operation for " << THREAD_SLEEP << " seconds" << std::endl << std::flush;
        sleep(THREAD_SLEEP);
        std::cout << __FUNCTION__ << ": Finished simulation, signaling the condition variable" << std::endl << std::flush;
        pthread_cond_signal(&condition);
        pthread_mutex_unlock(&mutex);
    }
考虑到这是我第一次使用POSIX线程,我想我遗漏了一些很明显的东西

我已经阅读了很多关于这方面的教程、文章和答案,但没有一本涵盖我的用例,也没有一本提供任何提示

请注意,为了简洁起见,我删除了一些处理pthread_cond_timedwait手册中提到的谓词的代码,因为这不会改变任何行为

我在CentOS 6.5机器上使用POSIX线程。我的开发和测试环境: 2.6.32-431.5.1.el6.centos.plus.x86_64#1 SMP x86_64 x86_64 x86_64 x86_64 GNU/Linux g++(GCC)4.4.7 20120313(红帽4.4.7-4)


编译命令:g++-o executable\u binary-pthread-lrt source\u code.cpp

 pthread_create(&t1, NULL, &f1, NULL);
 pthread_create(&t2, NULL, &f2, NULL);
我将使用thread
t1
来取消
t2
:在thread
t1
中添加一行,在计时器运行后,该行的内容为
pthread\u cancel(t2)

这将向
t2
发送一条消息,通知其终止。您可以保留两个join语句,这将意味着
t1
将耐心等待
t2
完成它的死亡阵痛,然后再继续:)


如果您需要更多信息,请告诉我:)

编辑:我首先建议不要使用pthread\u cond\u timedwait,但我认为在这种情况下,第一个线程的等待时间不会超过需要的时间,尽管我不会检查返回值,而是检查“finished”标志,该标志由第二个线程设置,并由互斥锁保护


示例中的问题是,互斥锁由第一个线程获取,互斥锁由
pthread\u cond\u timedwait()
调用释放。然后由第二个线程执行,从而阻塞第一个线程,直到第二个线程最后释放互斥体。

在发出条件信号之前,尝试在第二个线程中锁定互斥体。当互斥锁被锁定时,第一个线程无法唤醒。还有一件事:
pthread\u cond\u timedwait()
可以接收,因此如果结果不是
ETIMEDOUT
,第二个线程可能根本没有完成!(我想这就是@stefaanv在提到“完成”标志时所说的)@T045T:是的,这可能是一个插入我关于如何使用条件变量的答案的机会:我缺少的一点是,互斥锁不应该在漫长的任务之前被锁定,正如@stefaanv和n.m.corectly在上面指出的那样。实际上有两种方法适用于我的用例:要么使用pthread_cond_timedwait()并确保在运行冗长的任务之前解锁互斥锁,要么使用GMassucci下面的建议,这与使用条件变量一样有效,但没有那么优雅。对于这两种方法,冗长的任务必须完全独立于监视线程。
 pthread_create(&t1, NULL, &f1, NULL);
 pthread_create(&t2, NULL, &f2, NULL);