【问题标题】:Pthread timeoutPthread 超时
【发布时间】:2012-07-18 12:46:16
【问题描述】:

我想做的就是启动一个线程,看看它是否在一定时间内完成。

操作系统:Linux;语言:C++。

我不想使用不可移植的功能(如this answer 中的建议)。

除了使用互斥锁和 条件变量(建议here)?两个线程之间没有共享数据,所以从技术上讲我不需要互斥锁。 我想要的只是,对于启动线程的函数,如果

  • 线程已完成或

  • 过了一段时间。

...并尽可能保持代码简单。

【问题讨论】:

  • 我强烈推荐 boost 线程库,或者如果你有一个支持它们的编译器,C++11 中有一些并发特性。为此,您需要多精确的时间?分析可能是要走的路。
  • 条件变量、布尔标志和互斥体有什么问题?
  • sam:谢谢,我会阅读更多内容。 @Torsten:我想让它尽可能简单,对于这样一个简单的事实来说似乎太过分了。只是觉得我应该问。但是,作为最后的手段,我会谈到这一点。

标签: c++ linux pthreads


【解决方案1】:

如果你想使用 boost::thread,“通常”的 bool 标志、条件变量、互斥锁方法很简单:

bool ready = false;
boost::mutex              mutex;
boost::condition_variable cv;

// function to be executed by your thread
void foo() 
{
    // lengthy calculation
    boost::mutex::scoped_lock lock( mutex );
    ready = true;
    cv.notify_one();
}

// will return, if the thread stopped
bool wait_for_foo( time_point abs_time )
{
    boost::mutex::scoped_lock lock( mutex );

    while ( !ready && cv.wait_until( lock, abs_time ) != cv_status::no_timeout )
      ;

    return ready;
}

好吧,这并不比使用 posix 简单得多;-)

【讨论】:

  • 是的,Nicolai 的解决方案与条件变量的组合,以避免轮询和旋转。不过,我会将它与 posix 一起使用,因为代码稍后将被移植到 linux arm。 (一个互斥体,一个条件变量和一个布尔值,只是为了等待一个线程完成......但这似乎是最好的方法)
  • wait_until 不返回 bool,并且需要 time_point 而不是持续时间。我想你的意思是while (!ready && cv.wait_until(lock, abstime) != cv_status::timeout)
  • 准备一个“简单”的布尔类型不是很危险吗? IMO 您应该在之前添加“volatile”,否则编译器可能会进行值优化,并且在发布代码下您可能会得到不同的行为,对吧?
  • @zodi volatile 通常与线程无关。如果您有一个编译器/库对,可以让您编写多线程软件,您就可以保证这对像文档中描述的那样工作。
  • 哦,但它在线程方面做了很多 - 来自 msdn 的信息:“volatile 关键字是一个类型限定符,用于声明对象可以在程序中被操作系统、硬件等修改, 或并发执行的线程。(...) Microsoft 特定 - 声明为 volatile 的对象不会在某些优化中使用,因为它们的值可以随时更改。系统总是在它所在的点读取 volatile 对象的当前值请求,即使先前的指令要求来自同一对象的值。"
【解决方案2】:

您可以创建计时器线程,一旦计时器到达timeout,就取消该线程。不需要mutex.code就像:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define TIMEOUT 1*60 //in secend
int count = 0;
pthread_t t_main;   //Thread id for main thread
void * timer_thread()
{
    while (TIMEOUT > count)
    {
        sleep(1);  //sleep for a secand
        count++;
    }
    printf("killinn main thread\n");
    pthread_cancel(t_main); // cancel main thread

}
void * m_thread()
{
    pthread_t t_timer; //Thread id for timer thread
    if (-1 == pthread_create(&t_timer, NULL, timer_thread, NULL))
    {
        perror("pthread_create");
        return NULL;
    }
    //DO your work...
    while(1)
    {
        sleep(2);
    }
}

int main()
{
        if ( -1 == pthread_create(&t_main, NULL, m_thread, NULL))
    {
        perror("pthread_create");
        return -1;
    }
    if (-1 == pthread_join(t_main, NULL))
    {
        perror("pthread_join");
        return -1;
    }
    return 0;
}

【讨论】:

    【解决方案3】:

    你甚至不需要条件变量,你可以让另一个线程在进入时锁定一个互斥锁并在它完成时解锁它,并让启动线程使用pthread_mutex_timedlock(在旧版本的 POSIX 中是可选的,需要在 POSIX 2008 中)尝试获取互斥锁,如果其他线程尚未完成则超时。

    【讨论】:

    • 如何确保启动的线程在等待线程之前获取互斥锁?
    • 唯一的问题是,如果另一个线程在第一个线程检查它之前没有锁定互斥锁,它根本不会等待......所以我尝试在启动线程之前锁定它,但之后它会尝试再次锁定它(timedlock),这是不行的,因为它已经被同一个线程锁定了......我希望我写得足够清楚......
    • 添加一个初始化为false的简单布尔值,并让第二个线程在启动时将其翻转为true(当已经持有互斥锁时)。然后主线程将围绕pthread_mutex_timedlock 循环,释放互斥体并在该布尔值仍然为false 时重试。
    • 这可能非常无效,因为您必须轮询,其次,互斥锁通常在设计时考虑到快速路径。在多处理器机器上,在等待线程被阻塞之前可能会有一些旋转。
    • 是的,不得不承认你对 UP 机器的看法是正确的。继续忘记那些东西的存在:)
    猜你喜欢
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 2017-01-02
    相关资源
    最近更新 更多